x4js 1.4.2
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/application.d.ts +95 -0
- package/lib/application.js +137 -0
- package/lib/base64.d.ts +31 -0
- package/lib/base64.js +135 -0
- package/lib/base_component.d.ts +64 -0
- package/lib/base_component.js +77 -0
- package/lib/button.d.ts +145 -0
- package/lib/button.js +235 -0
- package/lib/calendar.d.ts +77 -0
- package/lib/calendar.js +236 -0
- package/lib/canvas.d.ts +88 -0
- package/lib/canvas.js +354 -0
- package/lib/cardview.d.ts +83 -0
- package/lib/cardview.js +152 -0
- package/lib/checkbox.d.ts +72 -0
- package/lib/checkbox.js +126 -0
- package/lib/color.d.ts +144 -0
- package/lib/color.js +584 -0
- package/lib/colorpicker.d.ts +98 -0
- package/lib/colorpicker.js +1457 -0
- package/lib/combobox.d.ts +97 -0
- package/lib/combobox.js +246 -0
- package/lib/component.d.ts +572 -0
- package/lib/component.js +1712 -0
- package/lib/datastore.d.ts +392 -0
- package/lib/datastore.js +986 -0
- package/lib/dialog.d.ts +171 -0
- package/lib/dialog.js +468 -0
- package/lib/dom_events.d.ts +284 -0
- package/lib/dom_events.js +13 -0
- package/lib/drag_manager.d.ts +26 -0
- package/lib/drag_manager.js +118 -0
- package/lib/drawtext.d.ts +43 -0
- package/lib/drawtext.js +261 -0
- package/lib/fileupload.d.ts +60 -0
- package/lib/fileupload.js +158 -0
- package/lib/form.d.ts +122 -0
- package/lib/form.js +293 -0
- package/lib/formatters.d.ts +31 -0
- package/lib/formatters.js +75 -0
- package/lib/gridview.d.ts +171 -0
- package/lib/gridview.js +786 -0
- package/lib/hosts/host.d.ts +44 -0
- package/lib/hosts/host.js +69 -0
- package/lib/i18n.d.ts +67 -0
- package/lib/i18n.js +169 -0
- package/lib/icon.d.ts +56 -0
- package/lib/icon.js +173 -0
- package/lib/image.d.ts +51 -0
- package/lib/image.js +149 -0
- package/lib/index.js +1 -0
- package/lib/input.d.ts +86 -0
- package/lib/input.js +172 -0
- package/lib/label.d.ts +54 -0
- package/lib/label.js +86 -0
- package/lib/layout.d.ts +77 -0
- package/lib/layout.js +261 -0
- package/lib/link.d.ts +46 -0
- package/lib/link.js +55 -0
- package/lib/listview.d.ts +173 -0
- package/lib/listview.js +532 -0
- package/lib/md5.d.ts +56 -0
- package/lib/md5.js +397 -0
- package/lib/menu.d.ts +122 -0
- package/lib/menu.js +276 -0
- package/lib/messagebox.d.ts +64 -0
- package/lib/messagebox.js +141 -0
- package/lib/panel.d.ts +42 -0
- package/lib/panel.js +61 -0
- package/lib/popup.d.ts +71 -0
- package/lib/popup.js +373 -0
- package/lib/property_editor.d.ts +67 -0
- package/lib/property_editor.js +247 -0
- package/lib/radiobtn.d.ts +68 -0
- package/lib/radiobtn.js +131 -0
- package/lib/rating.d.ts +49 -0
- package/lib/rating.js +93 -0
- package/lib/request.d.ts +48 -0
- package/lib/request.js +220 -0
- package/lib/router.d.ts +13 -0
- package/lib/router.js +27 -0
- package/lib/settings.d.ts +33 -0
- package/lib/settings.js +63 -0
- package/lib/sidebarview.d.ts +44 -0
- package/lib/sidebarview.js +73 -0
- package/lib/smartedit.d.ts +103 -0
- package/lib/smartedit.js +381 -0
- package/lib/spreadsheet.d.ts +214 -0
- package/lib/spreadsheet.js +1073 -0
- package/lib/styles.d.ts +81 -0
- package/lib/styles.js +262 -0
- package/lib/svgcomponent.d.ts +165 -0
- package/lib/svgcomponent.js +350 -0
- package/lib/tabbar.d.ts +41 -0
- package/lib/tabbar.js +66 -0
- package/lib/tabview.d.ts +45 -0
- package/lib/tabview.js +79 -0
- package/lib/textarea.d.ts +59 -0
- package/lib/textarea.js +119 -0
- package/lib/textedit.d.ts +118 -0
- package/lib/textedit.js +406 -0
- package/lib/texthiliter.d.ts +56 -0
- package/lib/texthiliter.js +219 -0
- package/lib/toaster.d.ts +38 -0
- package/lib/toaster.js +58 -0
- package/lib/tools.d.ts +382 -0
- package/lib/tools.js +1096 -0
- package/lib/tooltips.d.ts +42 -0
- package/lib/tooltips.js +148 -0
- package/lib/treeview.d.ts +128 -0
- package/lib/treeview.js +490 -0
- package/lib/x4_events.d.ts +253 -0
- package/lib/x4_events.js +363 -0
- package/package.json +21 -0
- package/src/README.md +2 -0
- package/src/application.ts +191 -0
- package/src/base64.ts +162 -0
- package/src/base_component.ts +118 -0
- package/src/button.ts +327 -0
- package/src/calendar.ts +312 -0
- package/src/canvas.ts +501 -0
- package/src/cardview.ts +220 -0
- package/src/checkbox.ts +178 -0
- package/src/color.ts +748 -0
- package/src/colorpicker.ts +1618 -0
- package/src/combobox.ts +348 -0
- package/src/component.ts +2330 -0
- package/src/datastore.ts +1318 -0
- package/src/dialog.ts +631 -0
- package/src/dom_events.ts +297 -0
- package/src/drag_manager.ts +168 -0
- package/src/drawtext.ts +342 -0
- package/src/fileupload.ts +208 -0
- package/src/form.ts +362 -0
- package/src/formatters.ts +96 -0
- package/src/gridview.ts +1051 -0
- package/src/hosts/electron.ts +161 -0
- package/src/hosts/host.ts +100 -0
- package/src/hosts/nwjs.ts +141 -0
- package/src/hosts/nwjs_types.ts +339 -0
- package/src/i18n.ts +205 -0
- package/src/icon.ts +237 -0
- package/src/image.ts +198 -0
- package/src/input.ts +236 -0
- package/src/label.ts +124 -0
- package/src/layout.ts +366 -0
- package/src/link.ts +82 -0
- package/src/listview.ts +749 -0
- package/src/md5.ts +432 -0
- package/src/menu.ts +394 -0
- package/src/messagebox.ts +199 -0
- package/src/panel.ts +81 -0
- package/src/popup.ts +488 -0
- package/src/property_editor.ts +333 -0
- package/src/radiobtn.ts +190 -0
- package/src/rating.ts +131 -0
- package/src/request.ts +296 -0
- package/src/router.ts +43 -0
- package/src/settings.ts +75 -0
- package/src/sidebarview.ts +97 -0
- package/src/smartedit.ts +532 -0
- package/src/spreadsheet.ts +1423 -0
- package/src/styles.ts +332 -0
- package/src/svgcomponent.ts +440 -0
- package/src/tabbar.ts +105 -0
- package/src/tabview.ts +106 -0
- package/src/textarea.ts +183 -0
- package/src/textedit.ts +535 -0
- package/src/texthiliter.ts +284 -0
- package/src/toaster.ts +76 -0
- package/src/tools.ts +1391 -0
- package/src/tooltips.ts +185 -0
- package/src/treeview.ts +670 -0
- package/src/x4.less +1940 -0
- package/src/x4_events.ts +558 -0
- package/tsconfig.json +14 -0
package/src/icon.ts
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ___ ___ __
|
|
3
|
+
* \ \/ / / _
|
|
4
|
+
* \ / /_| |_
|
|
5
|
+
* / \____ _|
|
|
6
|
+
* /__/\__\ |_|
|
|
7
|
+
*
|
|
8
|
+
* @file icon.ts
|
|
9
|
+
* @author Etienne Cochard
|
|
10
|
+
* @license
|
|
11
|
+
* Copyright (c) 2019-2021 R-libre ingenierie
|
|
12
|
+
*
|
|
13
|
+
* This program is free software; you can redistribute it and/or modify
|
|
14
|
+
* it under the terms of the GNU General Public License as published by
|
|
15
|
+
* the Free Software Foundation; either version 3 of the License, or
|
|
16
|
+
* (at your option) any later version.
|
|
17
|
+
*
|
|
18
|
+
* This program is distributed in the hope that it will be useful,
|
|
19
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21
|
+
* GNU General Public License for more details.
|
|
22
|
+
*
|
|
23
|
+
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
24
|
+
**/
|
|
25
|
+
|
|
26
|
+
import { Component, CProps } from './component'
|
|
27
|
+
import { Stylesheet } from './styles'
|
|
28
|
+
import { HtmlString } from './tools';
|
|
29
|
+
import { BasicEvent, EvChange, EventMap, EventSource } from './x4_events';
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// [ICON]
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
export type IconID = string | number;
|
|
36
|
+
|
|
37
|
+
export interface IconProps extends CProps {
|
|
38
|
+
icon: IconID;
|
|
39
|
+
size?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
export interface EvLoaded extends BasicEvent {
|
|
44
|
+
url: string;
|
|
45
|
+
svg: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function EvLoaded( url: string, svg: string, context = null ) {
|
|
49
|
+
return BasicEvent<EvLoaded>({ url, svg, context });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface LoadingEventMap extends EventMap {
|
|
53
|
+
loaded: EvLoaded;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class Loader extends EventSource<LoadingEventMap> {
|
|
57
|
+
svgs: Map<string,string>;
|
|
58
|
+
|
|
59
|
+
constructor( ) {
|
|
60
|
+
super( );
|
|
61
|
+
this.svgs = new Map( );
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
load( url: string ) {
|
|
65
|
+
if( this.svgs.has(url) ) {
|
|
66
|
+
const svg = this.svgs.get( url );
|
|
67
|
+
if( svg ) {
|
|
68
|
+
//console.log( 'cached=', url );
|
|
69
|
+
this.signal( 'loaded', EvLoaded(url,svg) );
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// mark it as loading
|
|
74
|
+
this.svgs.set( url, null );
|
|
75
|
+
|
|
76
|
+
// then start loading
|
|
77
|
+
const _load = async ( url ) => {
|
|
78
|
+
const r = await fetch( url );
|
|
79
|
+
if( r.ok ) {
|
|
80
|
+
const svg = await r.text();
|
|
81
|
+
this.svgs.set( url, svg );
|
|
82
|
+
|
|
83
|
+
//console.log( 'signal=', url );
|
|
84
|
+
this.signal( 'loaded', EvLoaded(url,svg) );
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
_load( url );
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const svgLoader = new Loader( );
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* standard icon
|
|
98
|
+
*/
|
|
99
|
+
export class Icon extends Component<IconProps>
|
|
100
|
+
{
|
|
101
|
+
private m_icon: string;
|
|
102
|
+
private m_iconName: IconID;
|
|
103
|
+
|
|
104
|
+
constructor( props: IconProps ) {
|
|
105
|
+
super( props );
|
|
106
|
+
|
|
107
|
+
this._setIcon( props.icon, false );
|
|
108
|
+
|
|
109
|
+
if( props.size ) {
|
|
110
|
+
this.setStyleValue( 'fontSize', props.size );
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private _setIcon(icon: IconID, remove_old: boolean) {
|
|
115
|
+
|
|
116
|
+
const reUrl = /\s*url\s*\(\s*(.+)\s*\)\s*/gi;
|
|
117
|
+
const reSvg = /\s*svg\s*\(\s*(.+)\s*\)\s*/gi;
|
|
118
|
+
const reSvg2 = /(.*\.svg)$/gi;
|
|
119
|
+
const reCls = /\s*cls\s*\(\s*(.+)\s*\)\s*/gi;
|
|
120
|
+
|
|
121
|
+
if( !icon ) {
|
|
122
|
+
this.m_iconName = '';
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this.removeClass( '@svg' );
|
|
127
|
+
|
|
128
|
+
let name, url;
|
|
129
|
+
if (typeof (icon) === 'number') {
|
|
130
|
+
icon = icon.toString(16);
|
|
131
|
+
name = icon;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
let match_svg = reSvg.exec( icon ) || reSvg2.exec(icon);
|
|
135
|
+
if( match_svg ) {
|
|
136
|
+
const url = match_svg[1].trim( );
|
|
137
|
+
this._setSVG( url );
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let match_cls = reCls.exec( icon );
|
|
142
|
+
if( match_cls ) {
|
|
143
|
+
const classes = match_cls[1].trim( );
|
|
144
|
+
this.addClass( classes );
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let match_url = reUrl.exec( icon );
|
|
149
|
+
if( match_url ) {
|
|
150
|
+
url = match_url[1].trim( );
|
|
151
|
+
name = url.replace( /[/\\\.\* ]/g, '_' );
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
name = icon;
|
|
155
|
+
icon = Stylesheet.getVar( 'icon-'+icon ) as string;
|
|
156
|
+
|
|
157
|
+
if( icon=='' || icon===undefined ) {
|
|
158
|
+
// name your icon 'icon-xxx'
|
|
159
|
+
// ex:
|
|
160
|
+
// :root { --icon-zoom-p: f00e; }
|
|
161
|
+
console.assert( false );
|
|
162
|
+
icon = '0';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this.m_iconName = name;
|
|
168
|
+
if( this.m_icon===icon ) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let css = Component.getCss(),
|
|
173
|
+
rulename: string;
|
|
174
|
+
|
|
175
|
+
if (remove_old && this.m_icon) {
|
|
176
|
+
rulename = 'icon-' + name;
|
|
177
|
+
this.removeClass(rulename);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// generate dynamic css icon rule
|
|
181
|
+
rulename = 'icon-' + name;
|
|
182
|
+
|
|
183
|
+
if( Icon.icon_cache[rulename]===undefined ) {
|
|
184
|
+
Icon.icon_cache[rulename] = true;
|
|
185
|
+
|
|
186
|
+
let rule: string;
|
|
187
|
+
|
|
188
|
+
if( url ) {
|
|
189
|
+
rule = `display: block; content: ' '; background-image: url(${url}); background-size: contain; width: 100%; height: 100%; background-repeat: no-repeat; color: white;`;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
rule = `content: "\\${icon}";`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
css.setRule(rulename, `.${rulename}::before {${rule}}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
this.addClass(rulename);
|
|
199
|
+
this.m_icon = icon;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* change the icon
|
|
204
|
+
* @param icon - new icon
|
|
205
|
+
*/
|
|
206
|
+
public set icon( icon: IconID ) {
|
|
207
|
+
this._setIcon( icon, true );
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
public get icon( ) : IconID {
|
|
211
|
+
return this.m_iconName;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private _setSVG( url: string ) {
|
|
215
|
+
|
|
216
|
+
const set = ( ev: EvLoaded ) => {
|
|
217
|
+
//console.log( 'set=', ev.url, 'url=', url );
|
|
218
|
+
|
|
219
|
+
if( ev.url==url ) {
|
|
220
|
+
this.addClass( '@svg-icon' );
|
|
221
|
+
this.setContent( HtmlString.from(ev.svg), false );
|
|
222
|
+
svgLoader.off( 'loaded', set );
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
svgLoader.on( 'loaded', set );
|
|
227
|
+
svgLoader.load( url );
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
*
|
|
233
|
+
*/
|
|
234
|
+
|
|
235
|
+
private static icon_cache = [];
|
|
236
|
+
}
|
|
237
|
+
|
package/src/image.ts
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ___ ___ __
|
|
3
|
+
* \ \/ / / _
|
|
4
|
+
* \ / /_| |_
|
|
5
|
+
* / \____ _|
|
|
6
|
+
* /__/\__\ |_|
|
|
7
|
+
*
|
|
8
|
+
* @file image.ts
|
|
9
|
+
* @author Etienne Cochard
|
|
10
|
+
* @license
|
|
11
|
+
* Copyright (c) 2019-2021 R-libre ingenierie
|
|
12
|
+
*
|
|
13
|
+
* This program is free software; you can redistribute it and/or modify
|
|
14
|
+
* it under the terms of the GNU General Public License as published by
|
|
15
|
+
* the Free Software Foundation; either version 3 of the License, or
|
|
16
|
+
* (at your option) any later version.
|
|
17
|
+
*
|
|
18
|
+
* This program is distributed in the hope that it will be useful,
|
|
19
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21
|
+
* GNU General Public License for more details.
|
|
22
|
+
*
|
|
23
|
+
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
24
|
+
**/
|
|
25
|
+
|
|
26
|
+
import { Component, CProps, html } from './component'
|
|
27
|
+
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// [IMAGE]
|
|
30
|
+
// ============================================================================
|
|
31
|
+
|
|
32
|
+
interface ImageProps extends CProps
|
|
33
|
+
{
|
|
34
|
+
src: string;
|
|
35
|
+
alt?: string;
|
|
36
|
+
lazy?: boolean; // mark image as lazy loading
|
|
37
|
+
alignment?: 'fill' | 'contain' | 'cover' | 'scale-down' | 'none';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const emptyImageSrc = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
|
41
|
+
|
|
42
|
+
function _isStaticImage( src: string ) {
|
|
43
|
+
return src.substr(0,5)=='data:';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Standard image class
|
|
50
|
+
*/
|
|
51
|
+
export class Image extends Component<ImageProps>
|
|
52
|
+
{
|
|
53
|
+
protected m_created: boolean;
|
|
54
|
+
protected m_lazysrc: string; // expected
|
|
55
|
+
|
|
56
|
+
constructor(props: ImageProps) {
|
|
57
|
+
super(props);
|
|
58
|
+
|
|
59
|
+
this.m_created = false;
|
|
60
|
+
|
|
61
|
+
this.m_props.lazy = props.lazy===false ? false : true;
|
|
62
|
+
this.m_props.alt = props.alt;
|
|
63
|
+
|
|
64
|
+
if( props.lazy!==false ) {
|
|
65
|
+
this.m_lazysrc = props.src;
|
|
66
|
+
props.src = emptyImageSrc;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.setDomEvent( 'create', ( ) => {
|
|
70
|
+
if( props.lazy ) {
|
|
71
|
+
this.setImage( this.m_lazysrc, true );
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** @ignore */
|
|
77
|
+
render( ) {
|
|
78
|
+
let mp = this.m_props;
|
|
79
|
+
|
|
80
|
+
const img = new Component( {
|
|
81
|
+
tag: 'img',
|
|
82
|
+
attrs: {
|
|
83
|
+
draggable: false,
|
|
84
|
+
alt: mp.alt ?? '',
|
|
85
|
+
decoding: mp.lazy ? 'async' : undefined,
|
|
86
|
+
},
|
|
87
|
+
style: {
|
|
88
|
+
objectFit: mp.alignment ? mp.alignment : undefined
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
this.setContent( img );
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* change the image
|
|
97
|
+
* @param src - image path
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
public setImage( src: string, force?: boolean ) {
|
|
101
|
+
|
|
102
|
+
if( !src ) {
|
|
103
|
+
src = emptyImageSrc;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if( !this.m_props.lazy ) {
|
|
107
|
+
this.m_props.src = src;
|
|
108
|
+
this.m_lazysrc = src;
|
|
109
|
+
|
|
110
|
+
if( this.dom ) {
|
|
111
|
+
(<HTMLElement>this.dom.firstChild).setAttribute( 'src', src );
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if( force || this.m_lazysrc!=src ) {
|
|
115
|
+
if( _isStaticImage(src) ) {
|
|
116
|
+
// not to download -> direct display
|
|
117
|
+
this.m_props.src = src;
|
|
118
|
+
this.m_lazysrc = src;
|
|
119
|
+
|
|
120
|
+
if( this.dom ) {
|
|
121
|
+
(<HTMLElement>this.dom.firstChild).setAttribute( 'src', this.m_props.src );
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// clear current image while waiting
|
|
126
|
+
this.m_props.src = emptyImageSrc;
|
|
127
|
+
if( this.dom ) {
|
|
128
|
+
(<HTMLElement>this.dom.firstChild).setAttribute( 'src', this.m_props.src );
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
this.m_lazysrc = src;
|
|
132
|
+
if( this.dom ) {
|
|
133
|
+
this._update_image( );
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private _update_image( ) {
|
|
140
|
+
|
|
141
|
+
console.assert( !!this.dom );
|
|
142
|
+
|
|
143
|
+
if( this.m_lazysrc && !_isStaticImage(this.m_lazysrc) ) {
|
|
144
|
+
// we do not push Components in a static array...
|
|
145
|
+
Image.lazy_images_waiting.push( { dom: this.dom, src: this.m_lazysrc } );
|
|
146
|
+
if( Image.lazy_image_timer===undefined ) {
|
|
147
|
+
Image.lazy_image_timer = setInterval( Image.lazyWatch as TimerHandler, 10 );
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private static lazy_images_waiting = [];
|
|
153
|
+
private static lazy_image_timer: number = undefined;
|
|
154
|
+
|
|
155
|
+
private static lazyWatch( ) {
|
|
156
|
+
|
|
157
|
+
let newList = [];
|
|
158
|
+
let done = 0;
|
|
159
|
+
|
|
160
|
+
Image.lazy_images_waiting.forEach( ( el ) => {
|
|
161
|
+
|
|
162
|
+
let dom = el.dom,
|
|
163
|
+
src = el.src;
|
|
164
|
+
|
|
165
|
+
// skip deleted elements
|
|
166
|
+
if( !dom || !document.contains(dom) ) {
|
|
167
|
+
// do not append to newList
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let rc = dom.getBoundingClientRect();
|
|
172
|
+
|
|
173
|
+
// if it is visible & inserted inside the document
|
|
174
|
+
if( !done && dom.offsetParent!==null &&
|
|
175
|
+
rc.bottom >= 0 && rc.right >= 0 &&
|
|
176
|
+
rc.top <= (window.innerHeight || document.documentElement.clientHeight) &&
|
|
177
|
+
rc.left <= (window.innerWidth || document.documentElement.clientWidth) ) {
|
|
178
|
+
|
|
179
|
+
// ok, we load the image
|
|
180
|
+
let img = <HTMLElement>dom.firstChild;
|
|
181
|
+
img.setAttribute( 'src', src );
|
|
182
|
+
done++;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// still not visible: may be next time
|
|
186
|
+
newList.push( el );
|
|
187
|
+
}
|
|
188
|
+
} );
|
|
189
|
+
|
|
190
|
+
Image.lazy_images_waiting = newList;
|
|
191
|
+
|
|
192
|
+
// no more elements to watch...
|
|
193
|
+
if( newList.length==0 ) {
|
|
194
|
+
clearInterval( Image.lazy_image_timer );
|
|
195
|
+
Image.lazy_image_timer = undefined;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
package/src/input.ts
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ___ ___ __
|
|
3
|
+
* \ \/ / / _
|
|
4
|
+
* \ / /_| |_
|
|
5
|
+
* / \____ _|
|
|
6
|
+
* /__/\__\ |_|
|
|
7
|
+
*
|
|
8
|
+
* @file input.ts
|
|
9
|
+
* @author Etienne Cochard
|
|
10
|
+
* @license
|
|
11
|
+
* Copyright (c) 2019-2021 R-libre ingenierie
|
|
12
|
+
*
|
|
13
|
+
* This program is free software; you can redistribute it and/or modify
|
|
14
|
+
* it under the terms of the GNU General Public License as published by
|
|
15
|
+
* the Free Software Foundation; either version 3 of the License, or
|
|
16
|
+
* (at your option) any later version.
|
|
17
|
+
*
|
|
18
|
+
* This program is distributed in the hope that it will be useful,
|
|
19
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21
|
+
* GNU General Public License for more details.
|
|
22
|
+
*
|
|
23
|
+
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
24
|
+
**/
|
|
25
|
+
|
|
26
|
+
import { Component, CProps, CEventMap, EvFocus } from './component'
|
|
27
|
+
//import { EvChange } from './x4_events';
|
|
28
|
+
|
|
29
|
+
export type EditType = 'text' | 'number' | 'email' | 'date' | 'password' | 'file' | 'checkbox' | 'radio';
|
|
30
|
+
|
|
31
|
+
export interface ValueHook {
|
|
32
|
+
get( ) : any;
|
|
33
|
+
set( v: any ) : void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface InputEventMap extends CEventMap {
|
|
37
|
+
// change?: EvChange;
|
|
38
|
+
// focus?: EvFocus;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface InputProps<P extends InputEventMap = InputEventMap> extends CProps<P> {
|
|
42
|
+
value?: string;
|
|
43
|
+
name?: string;
|
|
44
|
+
type?: EditType
|
|
45
|
+
placeHolder?: string;
|
|
46
|
+
autoFocus?: boolean;
|
|
47
|
+
readOnly?: boolean;
|
|
48
|
+
tabIndex?: number | boolean;
|
|
49
|
+
pattern?: string;
|
|
50
|
+
uppercase?: boolean;
|
|
51
|
+
spellcheck?: boolean;
|
|
52
|
+
value_hook?: ValueHook;
|
|
53
|
+
min?: number;
|
|
54
|
+
max?: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* base class for elements implementing an input
|
|
60
|
+
* CARE derived classes must set this.ui.input
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
export class Input extends Component<InputProps,InputEventMap>
|
|
64
|
+
{
|
|
65
|
+
constructor( props: InputProps ) {
|
|
66
|
+
super( props );
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** @ignore */
|
|
70
|
+
render( props: InputProps ) {
|
|
71
|
+
|
|
72
|
+
this.setProp( 'tag', 'input' );
|
|
73
|
+
this._setTabIndex( props.tabIndex );
|
|
74
|
+
|
|
75
|
+
this.setAttributes( {
|
|
76
|
+
value: props.value,
|
|
77
|
+
type: props.type || 'text',
|
|
78
|
+
name: props.name,
|
|
79
|
+
placeholder: props.placeHolder,
|
|
80
|
+
autofocus: props.autoFocus,
|
|
81
|
+
readonly: props.readOnly,
|
|
82
|
+
autocomplete: 'new-password', // chrome ignore 'off' but not something else than 'on'
|
|
83
|
+
tabindex: props.tabIndex,
|
|
84
|
+
spellcheck: props.spellcheck===false ? 'false' : undefined,
|
|
85
|
+
min: props.min,
|
|
86
|
+
max: props.max,
|
|
87
|
+
...props.attrs
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if( props.uppercase ) {
|
|
91
|
+
this.setStyleValue( 'textTransform', 'uppercase' );
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public getType( ) {
|
|
96
|
+
return this.m_props.type;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* return the current editor value
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
public get value( ) : string {
|
|
104
|
+
|
|
105
|
+
if( this.dom ) {
|
|
106
|
+
this.m_props.value = (<HTMLInputElement>this.dom).value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if( this.m_props.uppercase ) {
|
|
110
|
+
let upper = this.m_props.value.toUpperCase( ); // todo: locale ?
|
|
111
|
+
if( this.dom && upper!=this.m_props.value ) {
|
|
112
|
+
(<HTMLInputElement>this.dom).value = upper; // update the input
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.m_props.value = upper;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return this.m_props.value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Change the editor value
|
|
123
|
+
* @param value - new value to set
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
public set value( value: string ) {
|
|
127
|
+
|
|
128
|
+
this.m_props.value = value;
|
|
129
|
+
|
|
130
|
+
if( this.dom ) {
|
|
131
|
+
(<HTMLInputElement>this.dom).value = value;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public getStoreValue( ): any {
|
|
136
|
+
|
|
137
|
+
if( this.m_props.value_hook ) {
|
|
138
|
+
return this.m_props.value_hook.get( );
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
let type = this.getAttribute('type');
|
|
142
|
+
if( type ) { type = type.toLowerCase( ); }
|
|
143
|
+
|
|
144
|
+
let value,
|
|
145
|
+
dom = (<HTMLInputElement>this.dom);
|
|
146
|
+
|
|
147
|
+
if( type === "file") {
|
|
148
|
+
value = [];
|
|
149
|
+
|
|
150
|
+
let files = dom.files;
|
|
151
|
+
for( let file = 0; file < files.length; file++ ) {
|
|
152
|
+
value.push( files[file].name );
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else if ( type === 'checkbox' ) {
|
|
156
|
+
if( dom.checked ) {
|
|
157
|
+
value = 1;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
value = 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else if( type === 'radio' ) {
|
|
164
|
+
if( dom.checked ) {
|
|
165
|
+
value = this.value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if( type === 'date' ) {
|
|
169
|
+
debugger;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
value = this.value;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return value;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
public setStoreValue( v: any ) {
|
|
180
|
+
|
|
181
|
+
if( this.m_props.value_hook ) {
|
|
182
|
+
return this.m_props.value_hook.set( v );
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
let type = this.getAttribute('type'),
|
|
186
|
+
dom = (<HTMLInputElement>this.dom);
|
|
187
|
+
|
|
188
|
+
if( type ) { type = type.toLowerCase( ); }
|
|
189
|
+
if( type==='checkbox' ) {
|
|
190
|
+
let newval = v!==null && v!=='0' && v!==0 && v!==false;
|
|
191
|
+
if( newval!==dom.checked ) {
|
|
192
|
+
dom.setAttribute( 'checked', ''+newval );
|
|
193
|
+
dom.dispatchEvent( new Event( 'change' ) );
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
this.value = v;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
set readOnly( ro: boolean ) {
|
|
203
|
+
this.setAttribute('readonly', ro );
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* select all the text
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
public selectAll( ) {
|
|
211
|
+
(<HTMLInputElement>this.dom).select();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* select a part of the text
|
|
216
|
+
* @param start
|
|
217
|
+
* @param length
|
|
218
|
+
*/
|
|
219
|
+
|
|
220
|
+
public select( start: number, length: number = 9999 ) : void {
|
|
221
|
+
(<HTMLInputElement>this.dom).setSelectionRange( start, start+length );
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* get the selection as { start, length }
|
|
226
|
+
*/
|
|
227
|
+
|
|
228
|
+
public getSelection( ) {
|
|
229
|
+
let idom = (<HTMLInputElement>this.dom);
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
start: idom.selectionStart,
|
|
233
|
+
length: idom.selectionEnd - idom.selectionStart,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|