lexgui 0.1.44 → 0.1.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/build/components/codeeditor.js +117 -89
- package/build/lexgui.css +349 -123
- package/build/lexgui.js +690 -169
- package/build/lexgui.module.js +687 -167
- package/changelog.md +26 -2
- package/demo.js +104 -15
- package/package.json +1 -1
package/build/lexgui.module.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
var LX = {
|
|
11
|
-
version: "0.1.
|
|
11
|
+
version: "0.1.46",
|
|
12
12
|
ready: false,
|
|
13
13
|
components: [], // specific pre-build components
|
|
14
14
|
signals: {} // events and triggers
|
|
@@ -32,34 +32,118 @@ LX.clamp = clamp;
|
|
|
32
32
|
LX.round = round;
|
|
33
33
|
LX.remapRange = remapRange;
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
// Timer that works everywhere (from litegraph.js)
|
|
36
|
+
if ( typeof performance != "undefined" )
|
|
37
|
+
{
|
|
38
|
+
LX.getTime = performance.now.bind( performance );
|
|
39
|
+
}
|
|
40
|
+
else if( typeof Date != "undefined" && Date.now )
|
|
41
|
+
{
|
|
42
|
+
LX.getTime = Date.now.bind( Date );
|
|
43
|
+
}
|
|
44
|
+
else if ( typeof process != "undefined" )
|
|
45
|
+
{
|
|
46
|
+
LX.getTime = function() {
|
|
47
|
+
var t = process.hrtime();
|
|
48
|
+
return t[ 0 ] * 0.001 + t[ 1 ] * 1e-6;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
else
|
|
52
|
+
{
|
|
53
|
+
LX.getTime = function() {
|
|
54
|
+
return new Date().getTime();
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let ASYNC_ENABLED = true;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @method doAsync
|
|
62
|
+
* @description Call a function asynchronously
|
|
63
|
+
* @param {Function} fn Function to call
|
|
64
|
+
* @param {Number} ms Time to wait until calling the function (in milliseconds)
|
|
65
|
+
*/
|
|
66
|
+
function doAsync( fn, ms ) {
|
|
67
|
+
if( ASYNC_ENABLED )
|
|
68
|
+
{
|
|
69
|
+
setTimeout( fn, ms ?? 0 );
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
{
|
|
73
|
+
fn();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
LX.doAsync = doAsync;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @method getSupportedDOMName
|
|
81
|
+
* @description Convert a text string to a valid DOM name
|
|
82
|
+
* @param {String} text Original text
|
|
83
|
+
*/
|
|
84
|
+
function getSupportedDOMName( text )
|
|
36
85
|
{
|
|
37
|
-
return
|
|
86
|
+
return text.replace(/\s/g, '').replaceAll('@', '_').replaceAll('+', '_plus_').replaceAll('.', '');
|
|
38
87
|
}
|
|
39
88
|
|
|
40
89
|
LX.getSupportedDOMName = getSupportedDOMName;
|
|
41
90
|
|
|
42
|
-
|
|
91
|
+
/**
|
|
92
|
+
* @method has
|
|
93
|
+
* @description Ask if LexGUI is using a specific component
|
|
94
|
+
* @param {String} componentName Name of the LexGUI component
|
|
95
|
+
*/
|
|
96
|
+
function has( componentName )
|
|
43
97
|
{
|
|
44
|
-
return (LX.components.indexOf(
|
|
98
|
+
return ( LX.components.indexOf( componentName ) > -1 );
|
|
45
99
|
}
|
|
46
100
|
|
|
47
101
|
LX.has = has;
|
|
48
102
|
|
|
49
|
-
|
|
103
|
+
/**
|
|
104
|
+
* @method getExtension
|
|
105
|
+
* @description Get a extension from a path/url/filename
|
|
106
|
+
* @param {String} name
|
|
107
|
+
*/
|
|
108
|
+
function getExtension( name )
|
|
50
109
|
{
|
|
51
|
-
return
|
|
110
|
+
return name.includes('.') ? name.split('.').pop() : null;
|
|
52
111
|
}
|
|
53
112
|
|
|
54
113
|
LX.getExtension = getExtension;
|
|
55
114
|
|
|
56
|
-
|
|
115
|
+
/**
|
|
116
|
+
* @method deepCopy
|
|
117
|
+
* @description Create a deep copy with no references from an object
|
|
118
|
+
* @param {Object} obj
|
|
119
|
+
*/
|
|
120
|
+
function deepCopy( obj )
|
|
57
121
|
{
|
|
58
|
-
return JSON.parse(JSON.stringify(
|
|
122
|
+
return JSON.parse( JSON.stringify( obj ) )
|
|
59
123
|
}
|
|
60
124
|
|
|
61
125
|
LX.deepCopy = deepCopy;
|
|
62
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @method setTheme
|
|
129
|
+
* @description Set dark or light theme
|
|
130
|
+
* @param {String} colorScheme Name of the scheme
|
|
131
|
+
*/
|
|
132
|
+
function setTheme( colorScheme )
|
|
133
|
+
{
|
|
134
|
+
colorScheme = ( colorScheme == "light" ) ? "light" : "dark";
|
|
135
|
+
document.documentElement.setAttribute( "data-theme", colorScheme );
|
|
136
|
+
LX.emit( "@on_new_color_scheme", colorScheme );
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
LX.setTheme = setTheme;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @method setThemeColor
|
|
143
|
+
* @description Sets a new value for one of the main theme variables
|
|
144
|
+
* @param {String} colorName Name of the theme variable
|
|
145
|
+
* @param {String} color Color in rgba/hex
|
|
146
|
+
*/
|
|
63
147
|
function setThemeColor( colorName, color )
|
|
64
148
|
{
|
|
65
149
|
var r = document.querySelector( ':root' );
|
|
@@ -68,6 +152,11 @@ function setThemeColor( colorName, color )
|
|
|
68
152
|
|
|
69
153
|
LX.setThemeColor = setThemeColor;
|
|
70
154
|
|
|
155
|
+
/**
|
|
156
|
+
* @method getThemeColor
|
|
157
|
+
* @description Get the value for one of the main theme variables
|
|
158
|
+
* @param {String} colorName Name of the theme variable
|
|
159
|
+
*/
|
|
71
160
|
function getThemeColor( colorName )
|
|
72
161
|
{
|
|
73
162
|
const r = getComputedStyle( document.querySelector( ':root' ) );
|
|
@@ -75,7 +164,9 @@ function getThemeColor( colorName )
|
|
|
75
164
|
|
|
76
165
|
if( value.includes( "light-dark" ) && window.matchMedia )
|
|
77
166
|
{
|
|
78
|
-
|
|
167
|
+
const currentScheme = r.getPropertyValue( "color-scheme" );
|
|
168
|
+
|
|
169
|
+
if( ( window.matchMedia( "(prefers-color-scheme: light)" ).matches ) || ( currentScheme == "light" ) )
|
|
79
170
|
{
|
|
80
171
|
return value.substring( value.indexOf( '(' ) + 1, value.indexOf( ',' ) ).replace( /\s/g, '' );
|
|
81
172
|
}
|
|
@@ -90,7 +181,13 @@ function getThemeColor( colorName )
|
|
|
90
181
|
|
|
91
182
|
LX.getThemeColor = getThemeColor;
|
|
92
183
|
|
|
93
|
-
|
|
184
|
+
/**
|
|
185
|
+
* @method getBase64Image
|
|
186
|
+
* @description Convert an image to a base64 string
|
|
187
|
+
* @param {Image} img
|
|
188
|
+
*/
|
|
189
|
+
function getBase64Image( img )
|
|
190
|
+
{
|
|
94
191
|
var canvas = document.createElement( 'canvas' );
|
|
95
192
|
canvas.width = img.width;
|
|
96
193
|
canvas.height = img.height;
|
|
@@ -101,7 +198,13 @@ function getBase64Image( img ) {
|
|
|
101
198
|
|
|
102
199
|
LX.getBase64Image = getBase64Image;
|
|
103
200
|
|
|
104
|
-
|
|
201
|
+
/**
|
|
202
|
+
* @method hexToRgb
|
|
203
|
+
* @description Convert a hexadecimal string to a valid RGB color array
|
|
204
|
+
* @param {String} hexStr Hexadecimal color
|
|
205
|
+
*/
|
|
206
|
+
function hexToRgb( hexStr )
|
|
207
|
+
{
|
|
105
208
|
const red = parseInt( hexStr.substring( 1, 3 ), 16 ) / 255;
|
|
106
209
|
const green = parseInt( hexStr.substring( 3, 5 ), 16 ) / 255;
|
|
107
210
|
const blue = parseInt( hexStr.substring( 5, 7 ), 16 ) / 255;
|
|
@@ -110,7 +213,13 @@ function hexToRgb( hexStr ) {
|
|
|
110
213
|
|
|
111
214
|
LX.hexToRgb = hexToRgb;
|
|
112
215
|
|
|
113
|
-
|
|
216
|
+
/**
|
|
217
|
+
* @method rgbToHex
|
|
218
|
+
* @description Convert a RGB color array to a hexadecimal string
|
|
219
|
+
* @param {Array} rgb Array containing R, G, B, A*
|
|
220
|
+
*/
|
|
221
|
+
function rgbToHex( rgb )
|
|
222
|
+
{
|
|
114
223
|
let hex = "#";
|
|
115
224
|
for( let c of rgb ) {
|
|
116
225
|
c = Math.floor( c * 255 );
|
|
@@ -121,7 +230,14 @@ function rgbToHex( rgb ) {
|
|
|
121
230
|
|
|
122
231
|
LX.rgbToHex = rgbToHex;
|
|
123
232
|
|
|
124
|
-
|
|
233
|
+
/**
|
|
234
|
+
* @method measureRealWidth
|
|
235
|
+
* @description Measure the pixel width of a text
|
|
236
|
+
* @param {Object} value Text to measure
|
|
237
|
+
* @param {Number} paddingPlusMargin Padding offset
|
|
238
|
+
*/
|
|
239
|
+
function measureRealWidth( value, paddingPlusMargin = 8 )
|
|
240
|
+
{
|
|
125
241
|
var i = document.createElement( "span" );
|
|
126
242
|
i.className = "lexinputmeasure";
|
|
127
243
|
i.innerHTML = value;
|
|
@@ -133,7 +249,12 @@ function measureRealWidth( value, paddingPlusMargin = 8 ) {
|
|
|
133
249
|
|
|
134
250
|
LX.measureRealWidth = measureRealWidth;
|
|
135
251
|
|
|
136
|
-
|
|
252
|
+
/**
|
|
253
|
+
* @method simple_guidGenerator
|
|
254
|
+
* @description Get a random unique id
|
|
255
|
+
*/
|
|
256
|
+
function simple_guidGenerator()
|
|
257
|
+
{
|
|
137
258
|
var S4 = function() {
|
|
138
259
|
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
|
|
139
260
|
};
|
|
@@ -142,67 +263,40 @@ function simple_guidGenerator() {
|
|
|
142
263
|
|
|
143
264
|
LX.guidGenerator = simple_guidGenerator;
|
|
144
265
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
266
|
+
/**
|
|
267
|
+
* @method buildTextPattern
|
|
268
|
+
* @description Create a validation pattern using specific options
|
|
269
|
+
* @param {Object} options
|
|
270
|
+
* lowercase (Boolean): Text must contain a lowercase char
|
|
271
|
+
* uppercase (Boolean): Text must contain an uppercase char
|
|
272
|
+
* digit (Boolean): Text must contain a digit
|
|
273
|
+
* specialChar (Boolean): Text must contain a special char
|
|
274
|
+
* noSpaces (Boolean): Do not allow spaces in text
|
|
275
|
+
* minLength (Number): Text minimum length
|
|
276
|
+
* maxLength (Number): Text maximum length
|
|
277
|
+
* asRegExp (Boolean): Return pattern as Regular Expression instance
|
|
278
|
+
*/
|
|
279
|
+
function buildTextPattern( options = {} )
|
|
280
|
+
{
|
|
281
|
+
let patterns = [];
|
|
282
|
+
if ( options.lowercase ) patterns.push("(?=.*[a-z])");
|
|
283
|
+
if ( options.uppercase ) patterns.push("(?=.*[A-Z])");
|
|
284
|
+
if ( options.digit ) patterns.push("(?=.*\\d)");
|
|
285
|
+
if ( options.specialChar ) patterns.push("(?=.*[@#$%^&+=!])");
|
|
286
|
+
if ( options.noSpaces ) patterns.push("(?!.*\\s)");
|
|
287
|
+
|
|
288
|
+
let minLength = options.minLength || 0;
|
|
289
|
+
let maxLength = options.maxLength || ""; // Empty means no max length restriction
|
|
290
|
+
|
|
291
|
+
let pattern = `^${ patterns.join("") }.{${ minLength },${ maxLength }}$`;
|
|
292
|
+
return options.asRegExp ? new RegExp( pattern ) : pattern;
|
|
172
293
|
}
|
|
173
294
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
class vec2 {
|
|
177
|
-
|
|
178
|
-
constructor( x, y ) {
|
|
179
|
-
this.x = x ?? 0;
|
|
180
|
-
this.y = y ?? ( x ?? 0 );
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
get xy() { return [ this.x, this.y ]; }
|
|
184
|
-
get yx() { return [ this.y, this.x ]; }
|
|
185
|
-
|
|
186
|
-
set ( x, y ) { this.x = x; this.y = y; }
|
|
187
|
-
add ( v, v0 = new vec2() ) { v0.set( this.x + v.x, this.y + v.y ); return v0; }
|
|
188
|
-
sub ( v, v0 = new vec2() ) { v0.set( this.x - v.x, this.y - v.y ); return v0; }
|
|
189
|
-
mul ( v, v0 = new vec2() ) { if( v.constructor == Number ) { v = new vec2( v ) } v0.set( this.x * v.x, this.y * v.y ); return v0; }
|
|
190
|
-
div ( v, v0 = new vec2() ) { if( v.constructor == Number ) { v = new vec2( v ) } v0.set( this.x / v.x, this.y / v.y ); return v0; }
|
|
191
|
-
abs ( v0 = new vec2() ) { v0.set( Math.abs( this.x ), Math.abs( this.y ) ); return v0; }
|
|
192
|
-
dot ( v ) { return this.x * v.x + this.y * v.y; }
|
|
193
|
-
len2 () { return this.dot( this ) }
|
|
194
|
-
len () { return Math.sqrt( this.len2() ); }
|
|
195
|
-
nrm ( v0 = new vec2() ) { v0.set( this.x, this.y ); return v0.mul( 1.0 / this.len(), v0 ); }
|
|
196
|
-
dst ( v ) { return v.sub( this ).len(); }
|
|
197
|
-
clp ( min, max, v0 = new vec2() ) { v0.set( clamp( this.x, min, max ), clamp( this.y, min, max ) ); return v0; }
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
LX.vec2 = vec2;
|
|
201
|
-
|
|
202
|
-
// Other utils
|
|
295
|
+
LX.buildTextPattern = buildTextPattern;
|
|
203
296
|
|
|
204
297
|
/**
|
|
205
298
|
* @method makeDraggable
|
|
299
|
+
* @description Allow an element to be dragged
|
|
206
300
|
* @param {Element} domEl
|
|
207
301
|
* @param {Object} options
|
|
208
302
|
* autoAdjust (Bool): Sets in a correct position at the beggining
|
|
@@ -210,8 +304,8 @@ LX.vec2 = vec2;
|
|
|
210
304
|
* onMove (Function): Called each move event
|
|
211
305
|
* onDragStart (Function): Called when drag event starts
|
|
212
306
|
*/
|
|
213
|
-
function makeDraggable( domEl, options = { } )
|
|
214
|
-
|
|
307
|
+
function makeDraggable( domEl, options = { } )
|
|
308
|
+
{
|
|
215
309
|
let offsetX = 0;
|
|
216
310
|
let offsetY = 0;
|
|
217
311
|
let currentTarget = null;
|
|
@@ -301,8 +395,131 @@ function makeDraggable( domEl, options = { } ) {
|
|
|
301
395
|
|
|
302
396
|
LX.makeDraggable = makeDraggable;
|
|
303
397
|
|
|
304
|
-
|
|
398
|
+
/**
|
|
399
|
+
* @method makeCodeSnippet
|
|
400
|
+
* @description Create a code snippet in a specific language
|
|
401
|
+
* @param {String} code
|
|
402
|
+
* @param {Array} size
|
|
403
|
+
* @param {Object} options
|
|
404
|
+
* language (String):
|
|
405
|
+
* windowMode (Boolean):
|
|
406
|
+
* lineNumbers (Boolean):
|
|
407
|
+
* tabName (String):
|
|
408
|
+
*/
|
|
409
|
+
function makeCodeSnippet( code, size, options = { } )
|
|
410
|
+
{
|
|
411
|
+
if( !LX.has('CodeEditor') )
|
|
412
|
+
{
|
|
413
|
+
console.error( "Import the CodeEditor component to create snippets!" );
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const snippet = document.createElement( "div" );
|
|
418
|
+
snippet.className = "lexcodesnippet";
|
|
419
|
+
snippet.style.width = size[ 0 ];
|
|
420
|
+
snippet.style.height = size[ 1 ];
|
|
421
|
+
const area = new Area( { noAppend: true } );
|
|
422
|
+
let editor = new LX.CodeEditor( area, {
|
|
423
|
+
skipInfo: true,
|
|
424
|
+
disableEdition: true,
|
|
425
|
+
allowAddScripts: false,
|
|
426
|
+
name: options.tabName,
|
|
427
|
+
// showTab: options.showTab ?? true,
|
|
428
|
+
// lineNumbers: options.lineNumbers ?? true
|
|
429
|
+
} );
|
|
430
|
+
editor.setText( code, options.language ?? "Plain Text" );
|
|
431
|
+
|
|
432
|
+
if( options.linesAdded )
|
|
433
|
+
{
|
|
434
|
+
const code = editor.root.querySelector( ".code" );
|
|
435
|
+
for( let l of options.linesAdded )
|
|
436
|
+
{
|
|
437
|
+
if( l.constructor == Number )
|
|
438
|
+
{
|
|
439
|
+
code.childNodes[ l - 1 ].classList.add( "added" );
|
|
440
|
+
}
|
|
441
|
+
else if( l.constructor == Array ) // It's a range
|
|
442
|
+
{
|
|
443
|
+
for( let i = ( l[0] - 1 ); i <= ( l[1] - 1 ); i++ )
|
|
444
|
+
{
|
|
445
|
+
code.childNodes[ i ].classList.add( "added" );
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if( options.linesRemoved )
|
|
452
|
+
{
|
|
453
|
+
const code = editor.root.querySelector( ".code" );
|
|
454
|
+
for( let l of options.linesRemoved )
|
|
455
|
+
{
|
|
456
|
+
if( l.constructor == Number )
|
|
457
|
+
{
|
|
458
|
+
code.childNodes[ l - 1 ].classList.add( "removed" );
|
|
459
|
+
}
|
|
460
|
+
else if( l.constructor == Array ) // It's a range
|
|
461
|
+
{
|
|
462
|
+
for( let i = ( l[0] - 1 ); i <= ( l[1] - 1 ); i++ )
|
|
463
|
+
{
|
|
464
|
+
code.childNodes[ i ].classList.add( "removed" );
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if( options.windowMode )
|
|
471
|
+
{
|
|
472
|
+
const windowActionButtons = document.createElement( "div" );
|
|
473
|
+
windowActionButtons.className = "lexwindowbuttons";
|
|
474
|
+
const aButton = document.createElement( "span" );
|
|
475
|
+
aButton.style.background = "#ee4f50";
|
|
476
|
+
const bButton = document.createElement( "span" );
|
|
477
|
+
bButton.style.background = "#f5b720";
|
|
478
|
+
const cButton = document.createElement( "span" );
|
|
479
|
+
cButton.style.background = "#53ca29";
|
|
480
|
+
windowActionButtons.appendChild( aButton );
|
|
481
|
+
windowActionButtons.appendChild( bButton );
|
|
482
|
+
windowActionButtons.appendChild( cButton );
|
|
483
|
+
const tabs = editor.root.querySelector( ".lexareatabs" );
|
|
484
|
+
tabs.prepend( windowActionButtons );
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
snippet.appendChild( area.root );
|
|
488
|
+
return snippet;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
LX.makeCodeSnippet = makeCodeSnippet;
|
|
492
|
+
|
|
493
|
+
// Math classes
|
|
494
|
+
|
|
495
|
+
class vec2 {
|
|
496
|
+
|
|
497
|
+
constructor( x, y ) {
|
|
498
|
+
this.x = x ?? 0;
|
|
499
|
+
this.y = y ?? ( x ?? 0 );
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
get xy() { return [ this.x, this.y ]; }
|
|
503
|
+
get yx() { return [ this.y, this.x ]; }
|
|
504
|
+
|
|
505
|
+
set ( x, y ) { this.x = x; this.y = y; }
|
|
506
|
+
add ( v, v0 = new vec2() ) { v0.set( this.x + v.x, this.y + v.y ); return v0; }
|
|
507
|
+
sub ( v, v0 = new vec2() ) { v0.set( this.x - v.x, this.y - v.y ); return v0; }
|
|
508
|
+
mul ( v, v0 = new vec2() ) { if( v.constructor == Number ) { v = new vec2( v ) } v0.set( this.x * v.x, this.y * v.y ); return v0; }
|
|
509
|
+
div ( v, v0 = new vec2() ) { if( v.constructor == Number ) { v = new vec2( v ) } v0.set( this.x / v.x, this.y / v.y ); return v0; }
|
|
510
|
+
abs ( v0 = new vec2() ) { v0.set( Math.abs( this.x ), Math.abs( this.y ) ); return v0; }
|
|
511
|
+
dot ( v ) { return this.x * v.x + this.y * v.y; }
|
|
512
|
+
len2 () { return this.dot( this ) }
|
|
513
|
+
len () { return Math.sqrt( this.len2() ); }
|
|
514
|
+
nrm ( v0 = new vec2() ) { v0.set( this.x, this.y ); return v0.mul( 1.0 / this.len(), v0 ); }
|
|
515
|
+
dst ( v ) { return v.sub( this ).len(); }
|
|
516
|
+
clp ( min, max, v0 = new vec2() ) { v0.set( clamp( this.x, min, max ), clamp( this.y, min, max ) ); return v0; }
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
LX.vec2 = vec2;
|
|
305
520
|
|
|
521
|
+
function create_global_searchbar( root )
|
|
522
|
+
{
|
|
306
523
|
let globalSearch = document.createElement("div");
|
|
307
524
|
globalSearch.id = "global-search";
|
|
308
525
|
globalSearch.className = "hidden";
|
|
@@ -756,7 +973,7 @@ function prompt( text, title, callback, options = {} )
|
|
|
756
973
|
if( callback ) callback.call( this, value );
|
|
757
974
|
dialog.close();
|
|
758
975
|
}
|
|
759
|
-
}, { buttonClass: "
|
|
976
|
+
}, { buttonClass: "primary" });
|
|
760
977
|
|
|
761
978
|
p.addButton(null, "Cancel", () => {if(options.on_cancel) options.on_cancel(); dialog.close();} );
|
|
762
979
|
|
|
@@ -2205,18 +2422,18 @@ class Menubar {
|
|
|
2205
2422
|
entry.className = "lexmenuentry";
|
|
2206
2423
|
entry.id = pKey;
|
|
2207
2424
|
entry.innerHTML = "<span>" + key + "</span>";
|
|
2208
|
-
if(options.position == "left") {
|
|
2209
|
-
this.root.prepend( entry );
|
|
2210
|
-
}
|
|
2211
|
-
else {
|
|
2212
|
-
if(options.position == "right")
|
|
2213
|
-
entry.right = true;
|
|
2214
|
-
if(this.root.lastChild && this.root.lastChild.right) {
|
|
2215
|
-
this.root.lastChild.before( entry );
|
|
2216
|
-
}
|
|
2217
|
-
else {
|
|
2218
|
-
this.root.appendChild( entry );
|
|
2219
|
-
}
|
|
2425
|
+
if(options.position == "left") {
|
|
2426
|
+
this.root.prepend( entry );
|
|
2427
|
+
}
|
|
2428
|
+
else {
|
|
2429
|
+
if(options.position == "right")
|
|
2430
|
+
entry.right = true;
|
|
2431
|
+
if(this.root.lastChild && this.root.lastChild.right) {
|
|
2432
|
+
this.root.lastChild.before( entry );
|
|
2433
|
+
}
|
|
2434
|
+
else {
|
|
2435
|
+
this.root.appendChild( entry );
|
|
2436
|
+
}
|
|
2220
2437
|
}
|
|
2221
2438
|
|
|
2222
2439
|
const create_submenu = function( o, k, c, d ) {
|
|
@@ -2437,16 +2654,16 @@ class Menubar {
|
|
|
2437
2654
|
button.style.maxHeight = "calc(100% - 10px)";
|
|
2438
2655
|
button.style.alignItems = "center";
|
|
2439
2656
|
|
|
2440
|
-
if(options.float == "right")
|
|
2441
|
-
button.right = true;
|
|
2442
|
-
if(this.root.lastChild && this.root.lastChild.right) {
|
|
2443
|
-
this.root.lastChild.before( button );
|
|
2657
|
+
if(options.float == "right")
|
|
2658
|
+
button.right = true;
|
|
2659
|
+
if(this.root.lastChild && this.root.lastChild.right) {
|
|
2660
|
+
this.root.lastChild.before( button );
|
|
2444
2661
|
}
|
|
2445
2662
|
else if(options.float == "left") {
|
|
2446
2663
|
this.root.prepend(button);
|
|
2447
|
-
}
|
|
2448
|
-
else {
|
|
2449
|
-
this.root.appendChild( button );
|
|
2664
|
+
}
|
|
2665
|
+
else {
|
|
2666
|
+
this.root.appendChild( button );
|
|
2450
2667
|
}
|
|
2451
2668
|
|
|
2452
2669
|
const _b = button.querySelector('a');
|
|
@@ -2478,16 +2695,16 @@ class Menubar {
|
|
|
2478
2695
|
button.style.padding = "5px";
|
|
2479
2696
|
button.style.alignItems = "center";
|
|
2480
2697
|
|
|
2481
|
-
if(options.float == "right")
|
|
2482
|
-
button.right = true;
|
|
2483
|
-
if(this.root.lastChild && this.root.lastChild.right) {
|
|
2484
|
-
this.root.lastChild.before( button );
|
|
2485
|
-
}
|
|
2698
|
+
if(options.float == "right")
|
|
2699
|
+
button.right = true;
|
|
2700
|
+
if(this.root.lastChild && this.root.lastChild.right) {
|
|
2701
|
+
this.root.lastChild.before( button );
|
|
2702
|
+
}
|
|
2486
2703
|
else if(options.float == "left") {
|
|
2487
2704
|
this.root.prepend(button);
|
|
2488
2705
|
}
|
|
2489
|
-
else {
|
|
2490
|
-
this.root.appendChild( button );
|
|
2706
|
+
else {
|
|
2707
|
+
this.root.appendChild( button );
|
|
2491
2708
|
}
|
|
2492
2709
|
|
|
2493
2710
|
const _b = button.querySelector('a');
|
|
@@ -2507,44 +2724,86 @@ class Menubar {
|
|
|
2507
2724
|
|
|
2508
2725
|
addButtons( buttons, options = {} ) {
|
|
2509
2726
|
|
|
2510
|
-
if(!buttons)
|
|
2511
|
-
|
|
2727
|
+
if( !buttons )
|
|
2728
|
+
{
|
|
2729
|
+
throw( "No buttons to add!" );
|
|
2730
|
+
}
|
|
2512
2731
|
|
|
2513
|
-
if(!this.buttonContainer)
|
|
2732
|
+
if( !this.buttonContainer )
|
|
2514
2733
|
{
|
|
2515
|
-
this.buttonContainer = document.createElement(
|
|
2734
|
+
this.buttonContainer = document.createElement( "div" );
|
|
2516
2735
|
this.buttonContainer.className = "lexmenubuttons";
|
|
2517
|
-
this.buttonContainer.classList.add(options.float ??
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
this.
|
|
2522
|
-
}
|
|
2523
|
-
|
|
2524
|
-
|
|
2736
|
+
this.buttonContainer.classList.add( options.float ?? "center" );
|
|
2737
|
+
|
|
2738
|
+
if( options.position == "right" )
|
|
2739
|
+
{
|
|
2740
|
+
this.buttonContainer.right = true;
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
if( this.root.lastChild && this.root.lastChild.right )
|
|
2744
|
+
{
|
|
2745
|
+
this.root.lastChild.before( this.buttonContainer );
|
|
2746
|
+
}
|
|
2747
|
+
else
|
|
2748
|
+
{
|
|
2749
|
+
this.root.appendChild( this.buttonContainer );
|
|
2525
2750
|
}
|
|
2526
2751
|
}
|
|
2527
2752
|
|
|
2528
2753
|
for( let i = 0; i < buttons.length; ++i )
|
|
2529
2754
|
{
|
|
2530
|
-
let data = buttons[i];
|
|
2531
|
-
let button = document.createElement(
|
|
2755
|
+
let data = buttons[ i ];
|
|
2756
|
+
let button = document.createElement( "label" );
|
|
2532
2757
|
const title = data.title;
|
|
2533
2758
|
let disabled = data.disabled ?? false;
|
|
2534
2759
|
button.className = "lexmenubutton" + (disabled ? " disabled" : "");
|
|
2535
2760
|
button.title = title ?? "";
|
|
2536
|
-
button.innerHTML = "<a class='" + data.icon + " lexicon'></a>";
|
|
2537
2761
|
this.buttonContainer.appendChild( button );
|
|
2538
2762
|
|
|
2539
|
-
const
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2763
|
+
const icon = document.createElement( "a" );
|
|
2764
|
+
icon.className = data.icon + " lexicon";
|
|
2765
|
+
button.appendChild( icon );
|
|
2766
|
+
|
|
2767
|
+
let trigger = icon;
|
|
2768
|
+
|
|
2769
|
+
if( data.swap )
|
|
2770
|
+
{
|
|
2771
|
+
button.classList.add( "swap" );
|
|
2772
|
+
icon.classList.add( "swap-off" );
|
|
2773
|
+
|
|
2774
|
+
const input = document.createElement( "input" );
|
|
2775
|
+
input.type = "checkbox";
|
|
2776
|
+
button.prepend( input );
|
|
2777
|
+
trigger = input;
|
|
2778
|
+
|
|
2779
|
+
const swapIcon = document.createElement( "a" );
|
|
2780
|
+
swapIcon.className = data.swap + " swap-on lexicon";
|
|
2781
|
+
button.appendChild( swapIcon );
|
|
2782
|
+
|
|
2783
|
+
button.swap = function() {
|
|
2784
|
+
const swapInput = this.querySelector( "input" );
|
|
2785
|
+
swapInput.checked = !swapInput.checked;
|
|
2786
|
+
};
|
|
2787
|
+
|
|
2788
|
+
// Set if swap has to be performed
|
|
2789
|
+
button.setState = function( v ) {
|
|
2790
|
+
const swapInput = this.querySelector( "input" );
|
|
2791
|
+
swapInput.checked = v;
|
|
2792
|
+
};
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2795
|
+
trigger.addEventListener("click", e => {
|
|
2796
|
+
if( data.callback && !disabled )
|
|
2797
|
+
{
|
|
2798
|
+
const swapInput = button.querySelector( "input" );
|
|
2799
|
+
data.callback.call( this, e, swapInput?.checked );
|
|
2800
|
+
}
|
|
2544
2801
|
});
|
|
2545
2802
|
|
|
2546
|
-
if(title)
|
|
2803
|
+
if( title )
|
|
2804
|
+
{
|
|
2547
2805
|
this.buttons[ title ] = button;
|
|
2806
|
+
}
|
|
2548
2807
|
}
|
|
2549
2808
|
}
|
|
2550
2809
|
};
|
|
@@ -2698,6 +2957,7 @@ class Widget {
|
|
|
2698
2957
|
static PAD = 26;
|
|
2699
2958
|
static FORM = 27;
|
|
2700
2959
|
static DIAL = 28;
|
|
2960
|
+
static COUNTER = 29;
|
|
2701
2961
|
|
|
2702
2962
|
static NO_CONTEXT_TYPES = [
|
|
2703
2963
|
Widget.BUTTON,
|
|
@@ -2787,6 +3047,7 @@ class Widget {
|
|
|
2787
3047
|
case Widget.PAD: return "Pad";
|
|
2788
3048
|
case Widget.FORM: return "Form";
|
|
2789
3049
|
case Widget.DIAL: return "Dial";
|
|
3050
|
+
case Widget.COUNTER: return "Counter";
|
|
2790
3051
|
case Widget.CUSTOM: return this.customName;
|
|
2791
3052
|
}
|
|
2792
3053
|
|
|
@@ -4017,7 +4278,9 @@ class Panel {
|
|
|
4017
4278
|
* @param {Function} callback Callback function on change
|
|
4018
4279
|
* @param {*} options:
|
|
4019
4280
|
* disabled: Make the widget disabled [false]
|
|
4281
|
+
* required: Make the input required
|
|
4020
4282
|
* placeholder: Add input placeholder
|
|
4283
|
+
* pattern: Regular expression that value must match
|
|
4021
4284
|
* trigger: Choose onchange trigger (default, input) [default]
|
|
4022
4285
|
* inputWidth: Width of the text input
|
|
4023
4286
|
* skipReset: Don't add the reset value button when value changes
|
|
@@ -4032,11 +4295,18 @@ class Panel {
|
|
|
4032
4295
|
widget.onGetValue = () => {
|
|
4033
4296
|
return wValue.value;
|
|
4034
4297
|
};
|
|
4298
|
+
|
|
4035
4299
|
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
4036
4300
|
this.disabled ? wValue.innerText = newValue : wValue.value = newValue;
|
|
4037
4301
|
Panel._dispatch_event( wValue, "focusout", skipCallback );
|
|
4038
4302
|
};
|
|
4039
4303
|
|
|
4304
|
+
widget.valid = () => {
|
|
4305
|
+
if( wValue.pattern == "" ) { return true; }
|
|
4306
|
+
const regexp = new RegExp( wValue.pattern );
|
|
4307
|
+
return regexp.test( wValue.value );
|
|
4308
|
+
};
|
|
4309
|
+
|
|
4040
4310
|
let element = widget.domEl;
|
|
4041
4311
|
|
|
4042
4312
|
// Add reset functionality
|
|
@@ -4071,14 +4341,33 @@ class Panel {
|
|
|
4071
4341
|
wValue.style.width = "100%";
|
|
4072
4342
|
wValue.style.textAlign = options.float ?? "";
|
|
4073
4343
|
|
|
4074
|
-
|
|
4075
|
-
|
|
4344
|
+
wValue.setAttribute( "placeholder", options.placeholder ?? "" );
|
|
4345
|
+
|
|
4346
|
+
if( options.required )
|
|
4347
|
+
{
|
|
4348
|
+
wValue.setAttribute( "required", options.required );
|
|
4349
|
+
}
|
|
4350
|
+
|
|
4351
|
+
if( options.pattern )
|
|
4352
|
+
{
|
|
4353
|
+
wValue.setAttribute( "pattern", options.pattern );
|
|
4354
|
+
}
|
|
4076
4355
|
|
|
4077
4356
|
var resolve = ( function( val, event ) {
|
|
4357
|
+
|
|
4358
|
+
if( !widget.valid() )
|
|
4359
|
+
{
|
|
4360
|
+
return;
|
|
4361
|
+
}
|
|
4362
|
+
|
|
4078
4363
|
const skipCallback = event.detail;
|
|
4079
4364
|
let btn = element.querySelector( ".lexwidgetname .lexicon" );
|
|
4080
4365
|
if( btn ) btn.style.display = ( val != wValue.iValue ? "block" : "none" );
|
|
4081
|
-
if( !skipCallback )
|
|
4366
|
+
if( !skipCallback )
|
|
4367
|
+
{
|
|
4368
|
+
this._trigger( new IEvent( name, val, event ), callback );
|
|
4369
|
+
}
|
|
4370
|
+
|
|
4082
4371
|
}).bind( this );
|
|
4083
4372
|
|
|
4084
4373
|
const trigger = options.trigger ?? 'default';
|
|
@@ -4290,18 +4579,13 @@ class Panel {
|
|
|
4290
4579
|
|
|
4291
4580
|
var wValue = document.createElement( 'button' );
|
|
4292
4581
|
wValue.title = options.title ?? "";
|
|
4293
|
-
wValue.className = "lexbutton";
|
|
4582
|
+
wValue.className = "lexbutton " + ( options.buttonClass ?? "" );
|
|
4294
4583
|
|
|
4295
4584
|
if( options.selected )
|
|
4296
4585
|
{
|
|
4297
4586
|
wValue.classList.add( "selected" );
|
|
4298
4587
|
}
|
|
4299
4588
|
|
|
4300
|
-
if( options.buttonClass )
|
|
4301
|
-
{
|
|
4302
|
-
wValue.classList.add( options.buttonClass );
|
|
4303
|
-
}
|
|
4304
|
-
|
|
4305
4589
|
wValue.innerHTML =
|
|
4306
4590
|
(options.icon ? "<a class='" + options.icon + "'></a>" :
|
|
4307
4591
|
( options.img ? "<img src='" + options.img + "'>" : "<span>" + (value || "") + "</span>" ));
|
|
@@ -4540,7 +4824,7 @@ class Panel {
|
|
|
4540
4824
|
|
|
4541
4825
|
this.addLabel( entry, { textClass: "formlabel" } );
|
|
4542
4826
|
|
|
4543
|
-
this.addText( null, entryData.constructor == Object ? entryData.value : entryData, ( value ) => {
|
|
4827
|
+
entryData.textWidget = this.addText( null, entryData.constructor == Object ? entryData.value : entryData, ( value ) => {
|
|
4544
4828
|
container.formData[ entry ] = value;
|
|
4545
4829
|
}, entryData );
|
|
4546
4830
|
|
|
@@ -4550,11 +4834,22 @@ class Panel {
|
|
|
4550
4834
|
this.addBlank( );
|
|
4551
4835
|
|
|
4552
4836
|
this.addButton( null, options.actionName ?? "Submit", ( value, event ) => {
|
|
4837
|
+
|
|
4838
|
+
for( let entry in data )
|
|
4839
|
+
{
|
|
4840
|
+
let entryData = data[ entry ];
|
|
4841
|
+
|
|
4842
|
+
if( !entryData.textWidget.valid() )
|
|
4843
|
+
{
|
|
4844
|
+
return;
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
|
|
4553
4848
|
if( callback )
|
|
4554
4849
|
{
|
|
4555
4850
|
callback( container.formData, event );
|
|
4556
4851
|
}
|
|
4557
|
-
}, { buttonClass: "
|
|
4852
|
+
}, { buttonClass: "primary", width: "calc(100% - 10px)" } );
|
|
4558
4853
|
|
|
4559
4854
|
this.clearQueue();
|
|
4560
4855
|
|
|
@@ -4709,13 +5004,36 @@ class Panel {
|
|
|
4709
5004
|
delete list.unfocus_event;
|
|
4710
5005
|
return;
|
|
4711
5006
|
}
|
|
4712
|
-
|
|
4713
|
-
list.
|
|
5007
|
+
|
|
5008
|
+
list.toggleAttribute( "hidden" );
|
|
5009
|
+
list.classList.remove( "place-above" );
|
|
5010
|
+
|
|
5011
|
+
const listHeight = 26 * values.length;
|
|
5012
|
+
const rect = selectedOption.getBoundingClientRect();
|
|
5013
|
+
const topPosition = rect.y;
|
|
5014
|
+
|
|
5015
|
+
let maxY = window.innerHeight;
|
|
5016
|
+
let overflowContainer = list.getParentArea();
|
|
5017
|
+
|
|
5018
|
+
if( overflowContainer )
|
|
5019
|
+
{
|
|
5020
|
+
const parentRect = overflowContainer.getBoundingClientRect();
|
|
5021
|
+
maxY = parentRect.y + parentRect.height;
|
|
5022
|
+
}
|
|
5023
|
+
|
|
5024
|
+
list.style.top = ( topPosition + selectedOption.offsetHeight ) + 'px';
|
|
5025
|
+
|
|
5026
|
+
const showAbove = ( topPosition + listHeight ) > maxY;
|
|
5027
|
+
if( showAbove )
|
|
5028
|
+
{
|
|
5029
|
+
list.style.top = ( topPosition - listHeight ) + 'px';
|
|
5030
|
+
list.classList.add( "place-above" );
|
|
5031
|
+
}
|
|
5032
|
+
|
|
4714
5033
|
list.style.width = (event.currentTarget.clientWidth) + 'px';
|
|
4715
5034
|
list.style.minWidth = (_getMaxListWidth()) + 'px';
|
|
4716
|
-
list.toggleAttribute('hidden');
|
|
4717
5035
|
list.focus();
|
|
4718
|
-
}, { buttonClass:
|
|
5036
|
+
}, { buttonClass: "array", skipInlineCount: true });
|
|
4719
5037
|
|
|
4720
5038
|
this.clearQueue();
|
|
4721
5039
|
|
|
@@ -5361,40 +5679,45 @@ class Panel {
|
|
|
5361
5679
|
|
|
5362
5680
|
// Show tags
|
|
5363
5681
|
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5682
|
+
const tagsContainer = document.createElement('div');
|
|
5683
|
+
tagsContainer.className = "lextags";
|
|
5684
|
+
tagsContainer.style.width = "calc( 100% - " + LX.DEFAULT_NAME_WIDTH + ")";
|
|
5367
5685
|
|
|
5368
5686
|
const create_tags = () => {
|
|
5369
5687
|
|
|
5370
|
-
|
|
5688
|
+
tagsContainer.innerHTML = "";
|
|
5371
5689
|
|
|
5372
5690
|
for( let i = 0; i < value.length; ++i )
|
|
5373
5691
|
{
|
|
5374
|
-
|
|
5375
|
-
|
|
5692
|
+
const tagName = value[i];
|
|
5693
|
+
const tag = document.createElement('span');
|
|
5376
5694
|
tag.className = "lextag";
|
|
5377
|
-
tag.innerHTML =
|
|
5695
|
+
tag.innerHTML = tagName;
|
|
5696
|
+
|
|
5697
|
+
const removeButton = document.createElement('a');
|
|
5698
|
+
removeButton.className = "lextagrmb fa-solid fa-xmark lexicon";
|
|
5699
|
+
tag.appendChild( removeButton );
|
|
5378
5700
|
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
value.splice( value.indexOf(
|
|
5701
|
+
removeButton.addEventListener( 'click', e => {
|
|
5702
|
+
tag.remove();
|
|
5703
|
+
value.splice( value.indexOf( tagName ), 1 );
|
|
5382
5704
|
let btn = element.querySelector( ".lexwidgetname .lexicon" );
|
|
5383
5705
|
if( btn ) btn.style.display = ( value != defaultValue ? "block" : "none" );
|
|
5384
5706
|
that._trigger( new IEvent( name, value, e ), callback );
|
|
5385
|
-
});
|
|
5707
|
+
} );
|
|
5386
5708
|
|
|
5387
|
-
|
|
5709
|
+
tagsContainer.appendChild( tag );
|
|
5388
5710
|
}
|
|
5389
5711
|
|
|
5390
|
-
let
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5712
|
+
let tagInput = document.createElement( 'input' );
|
|
5713
|
+
tagInput.value = "";
|
|
5714
|
+
tagInput.placeholder = "Add tag...";
|
|
5715
|
+
tagsContainer.appendChild( tagInput );
|
|
5394
5716
|
|
|
5395
|
-
|
|
5717
|
+
tagInput.onkeydown = function( e ) {
|
|
5396
5718
|
const val = this.value.replace(/\s/g, '');
|
|
5397
|
-
if( e.key == ' ')
|
|
5719
|
+
if( e.key == ' ' || e.key == 'Enter' )
|
|
5720
|
+
{
|
|
5398
5721
|
e.preventDefault();
|
|
5399
5722
|
if( !val.length || value.indexOf( val ) > -1 )
|
|
5400
5723
|
return;
|
|
@@ -5406,18 +5729,19 @@ class Panel {
|
|
|
5406
5729
|
}
|
|
5407
5730
|
};
|
|
5408
5731
|
|
|
5409
|
-
|
|
5732
|
+
tagInput.focus();
|
|
5410
5733
|
}
|
|
5411
5734
|
|
|
5412
5735
|
create_tags();
|
|
5413
5736
|
|
|
5414
5737
|
// Remove branch padding and margins
|
|
5415
|
-
if(!widget.name)
|
|
5738
|
+
if( !widget.name )
|
|
5739
|
+
{
|
|
5416
5740
|
element.className += " noname";
|
|
5417
|
-
|
|
5741
|
+
tagsContainer.style.width = "100%";
|
|
5418
5742
|
}
|
|
5419
5743
|
|
|
5420
|
-
element.appendChild(
|
|
5744
|
+
element.appendChild( tagsContainer );
|
|
5421
5745
|
|
|
5422
5746
|
return widget;
|
|
5423
5747
|
}
|
|
@@ -6604,7 +6928,7 @@ class Panel {
|
|
|
6604
6928
|
progress.classList.add( "editable" );
|
|
6605
6929
|
progress.addEventListener( "mousedown", inner_mousedown );
|
|
6606
6930
|
|
|
6607
|
-
|
|
6931
|
+
const that = this;
|
|
6608
6932
|
|
|
6609
6933
|
function inner_mousedown( e )
|
|
6610
6934
|
{
|
|
@@ -6612,24 +6936,28 @@ class Panel {
|
|
|
6612
6936
|
doc.addEventListener( 'mousemove', inner_mousemove );
|
|
6613
6937
|
doc.addEventListener( 'mouseup', inner_mouseup );
|
|
6614
6938
|
document.body.classList.add( 'noevents' );
|
|
6939
|
+
progress.classList.add( "grabbing" );
|
|
6615
6940
|
e.stopImmediatePropagation();
|
|
6616
6941
|
e.stopPropagation();
|
|
6942
|
+
|
|
6943
|
+
const rect = progress.getBoundingClientRect();
|
|
6944
|
+
const newValue = round( remapRange( e.offsetX, 0, rect.width, progress.min, progress.max ) );
|
|
6945
|
+
that.setValue( name, newValue );
|
|
6617
6946
|
}
|
|
6618
6947
|
|
|
6619
6948
|
function inner_mousemove( e )
|
|
6620
6949
|
{
|
|
6621
|
-
let dt =
|
|
6950
|
+
let dt = e.movementX;
|
|
6622
6951
|
|
|
6623
6952
|
if ( dt != 0 )
|
|
6624
6953
|
{
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
that.setValue( name, v );
|
|
6954
|
+
const rect = progress.getBoundingClientRect();
|
|
6955
|
+
const newValue = round( remapRange( e.offsetX - rect.x, 0, rect.width, progress.min, progress.max ) );
|
|
6956
|
+
that.setValue( name, newValue );
|
|
6629
6957
|
|
|
6630
6958
|
if( options.callback )
|
|
6631
6959
|
{
|
|
6632
|
-
options.callback(
|
|
6960
|
+
options.callback( newValue, e );
|
|
6633
6961
|
}
|
|
6634
6962
|
}
|
|
6635
6963
|
|
|
@@ -6643,6 +6971,7 @@ class Panel {
|
|
|
6643
6971
|
doc.removeEventListener( 'mousemove', inner_mousemove );
|
|
6644
6972
|
doc.removeEventListener( 'mouseup', inner_mouseup );
|
|
6645
6973
|
document.body.classList.remove( 'noevents' );
|
|
6974
|
+
progress.classList.remove( "grabbing" );
|
|
6646
6975
|
}
|
|
6647
6976
|
}
|
|
6648
6977
|
|
|
@@ -6932,6 +7261,91 @@ class Panel {
|
|
|
6932
7261
|
|
|
6933
7262
|
this.addSeparator();
|
|
6934
7263
|
}
|
|
7264
|
+
|
|
7265
|
+
/**
|
|
7266
|
+
* @method addCounter
|
|
7267
|
+
* @param {String} name Widget name
|
|
7268
|
+
* @param {Number} value Counter value
|
|
7269
|
+
* @param {Function} callback Callback function on change
|
|
7270
|
+
* @param {*} options:
|
|
7271
|
+
* disabled: Make the widget disabled [false]
|
|
7272
|
+
* min, max: Min and Max values
|
|
7273
|
+
* step: Step for adding/substracting
|
|
7274
|
+
* label: Text to show below the counter
|
|
7275
|
+
*/
|
|
7276
|
+
|
|
7277
|
+
addCounter( name, value, callback, options = { } ) {
|
|
7278
|
+
|
|
7279
|
+
let widget = this.create_widget( name, Widget.COUNTER, options );
|
|
7280
|
+
|
|
7281
|
+
widget.onGetValue = () => {
|
|
7282
|
+
return counterText.count;
|
|
7283
|
+
};
|
|
7284
|
+
|
|
7285
|
+
widget.onSetValue = ( newValue, skipCallback ) => {
|
|
7286
|
+
_onChange( newValue, skipCallback );
|
|
7287
|
+
};
|
|
7288
|
+
|
|
7289
|
+
let element = widget.domEl;
|
|
7290
|
+
|
|
7291
|
+
const min = options.min ?? 0;
|
|
7292
|
+
const max = options.max ?? 100;
|
|
7293
|
+
const step = options.step ?? 1;
|
|
7294
|
+
|
|
7295
|
+
const _onChange = ( value, skipCallback, event ) => {
|
|
7296
|
+
value = clamp( value, min, max );
|
|
7297
|
+
counterText.count = value;
|
|
7298
|
+
counterText.innerHTML = value;
|
|
7299
|
+
if( !skipCallback )
|
|
7300
|
+
{
|
|
7301
|
+
this._trigger( new IEvent( name, value, event ), callback );
|
|
7302
|
+
}
|
|
7303
|
+
}
|
|
7304
|
+
|
|
7305
|
+
const container = document.createElement( 'div' );
|
|
7306
|
+
container.className = "lexcounter";
|
|
7307
|
+
element.appendChild( container );
|
|
7308
|
+
|
|
7309
|
+
this.queue( container );
|
|
7310
|
+
|
|
7311
|
+
this.addButton(null, "<a style='margin-top: 0px;' class='fa-solid fa-minus'></a>", (value, e) => {
|
|
7312
|
+
let mult = step ?? 1;
|
|
7313
|
+
if( e.shiftKey ) mult *= 10;
|
|
7314
|
+
_onChange( counterText.count - mult, false, e );
|
|
7315
|
+
}, { className: "micro", skipInlineCount: true, title: "Minus" });
|
|
7316
|
+
|
|
7317
|
+
this.clearQueue();
|
|
7318
|
+
|
|
7319
|
+
const containerBox = document.createElement( 'div' );
|
|
7320
|
+
containerBox.className = "lexcounterbox";
|
|
7321
|
+
container.appendChild( containerBox );
|
|
7322
|
+
|
|
7323
|
+
const counterText = document.createElement( 'span' );
|
|
7324
|
+
counterText.className = "lexcountervalue";
|
|
7325
|
+
counterText.innerHTML = value;
|
|
7326
|
+
counterText.count = value;
|
|
7327
|
+
containerBox.appendChild( counterText );
|
|
7328
|
+
|
|
7329
|
+
if( options.label )
|
|
7330
|
+
{
|
|
7331
|
+
const counterLabel = document.createElement( 'span' );
|
|
7332
|
+
counterLabel.className = "lexcounterlabel";
|
|
7333
|
+
counterLabel.innerHTML = options.label;
|
|
7334
|
+
containerBox.appendChild( counterLabel );
|
|
7335
|
+
}
|
|
7336
|
+
|
|
7337
|
+
this.queue( container );
|
|
7338
|
+
|
|
7339
|
+
this.addButton(null, "<a style='margin-top: 0px;' class='fa-solid fa-plus'></a>", (value, e) => {
|
|
7340
|
+
let mult = step ?? 1;
|
|
7341
|
+
if( e.shiftKey ) mult *= 10;
|
|
7342
|
+
_onChange( counterText.count + mult, false, e );
|
|
7343
|
+
}, { className: "micro", skipInlineCount: true, title: "Plus" });
|
|
7344
|
+
|
|
7345
|
+
this.clearQueue();
|
|
7346
|
+
|
|
7347
|
+
return widget;
|
|
7348
|
+
}
|
|
6935
7349
|
}
|
|
6936
7350
|
|
|
6937
7351
|
LX.Panel = Panel;
|
|
@@ -7167,6 +7581,104 @@ class Branch {
|
|
|
7167
7581
|
|
|
7168
7582
|
LX.Branch = Branch;
|
|
7169
7583
|
|
|
7584
|
+
/**
|
|
7585
|
+
* @class Footer
|
|
7586
|
+
*/
|
|
7587
|
+
|
|
7588
|
+
class Footer {
|
|
7589
|
+
/**
|
|
7590
|
+
* @param {*} options:
|
|
7591
|
+
* columns: Array with data per column { title, items: [ { title, link } ] }
|
|
7592
|
+
* credits: html string
|
|
7593
|
+
* socials: Array with data per item { title, link, iconHtml }
|
|
7594
|
+
*/
|
|
7595
|
+
constructor( options = {} ) {
|
|
7596
|
+
|
|
7597
|
+
const root = document.createElement( "footer" );
|
|
7598
|
+
root.className = "lexfooter";
|
|
7599
|
+
|
|
7600
|
+
const wrapper = document.createElement( "div" );
|
|
7601
|
+
wrapper.className = "wrapper";
|
|
7602
|
+
root.appendChild( wrapper );
|
|
7603
|
+
|
|
7604
|
+
if( options.columns && options.columns.constructor == Array )
|
|
7605
|
+
{
|
|
7606
|
+
const cols = document.createElement( "div" );
|
|
7607
|
+
cols.className = "columns";
|
|
7608
|
+
cols.style.gridTemplateColumns = "1fr ".repeat( options.columns.length );
|
|
7609
|
+
wrapper.appendChild( cols );
|
|
7610
|
+
|
|
7611
|
+
for( let col of options.columns )
|
|
7612
|
+
{
|
|
7613
|
+
const colDom = document.createElement( "div" );
|
|
7614
|
+
colDom.className = "col";
|
|
7615
|
+
cols.appendChild( colDom );
|
|
7616
|
+
|
|
7617
|
+
const colTitle = document.createElement( "h2" );
|
|
7618
|
+
colTitle.innerHTML = col.title;
|
|
7619
|
+
colDom.appendChild( colTitle );
|
|
7620
|
+
|
|
7621
|
+
if( !col.items || !col.items.length )
|
|
7622
|
+
{
|
|
7623
|
+
continue;
|
|
7624
|
+
}
|
|
7625
|
+
|
|
7626
|
+
const itemListDom = document.createElement( "ul" );
|
|
7627
|
+
colDom.appendChild( itemListDom );
|
|
7628
|
+
|
|
7629
|
+
for( let item of col.items )
|
|
7630
|
+
{
|
|
7631
|
+
const itemDom = document.createElement( "li" );
|
|
7632
|
+
itemDom.innerHTML = `<a class="" href="${ item.link }">${ item.title }</a>`;
|
|
7633
|
+
itemListDom.appendChild( itemDom );
|
|
7634
|
+
}
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
|
|
7638
|
+
if( options.credits || options.socials )
|
|
7639
|
+
{
|
|
7640
|
+
const hr = document.createElement( "hr" );
|
|
7641
|
+
wrapper.appendChild( hr );
|
|
7642
|
+
|
|
7643
|
+
const creditsSocials = document.createElement( "div" );
|
|
7644
|
+
creditsSocials.className = "credits-and-socials";
|
|
7645
|
+
wrapper.appendChild( creditsSocials );
|
|
7646
|
+
|
|
7647
|
+
if( options.credits )
|
|
7648
|
+
{
|
|
7649
|
+
const credits = document.createElement( "p" );
|
|
7650
|
+
credits.innerHTML = options.credits;
|
|
7651
|
+
creditsSocials.appendChild( credits );
|
|
7652
|
+
}
|
|
7653
|
+
|
|
7654
|
+
if( options.socials )
|
|
7655
|
+
{
|
|
7656
|
+
const socials = document.createElement( "div" );
|
|
7657
|
+
socials.className = "social";
|
|
7658
|
+
|
|
7659
|
+
for( let social of options.socials )
|
|
7660
|
+
{
|
|
7661
|
+
const itemDom = document.createElement( "a" );
|
|
7662
|
+
itemDom.title = social.title;
|
|
7663
|
+
itemDom.innerHTML = social.icon;
|
|
7664
|
+
itemDom.href = social.link;
|
|
7665
|
+
itemDom.target = "_blank";
|
|
7666
|
+
socials.appendChild( itemDom );
|
|
7667
|
+
}
|
|
7668
|
+
|
|
7669
|
+
creditsSocials.appendChild( socials );
|
|
7670
|
+
}
|
|
7671
|
+
}
|
|
7672
|
+
|
|
7673
|
+
// Append directly to body
|
|
7674
|
+
const parent = options.parent ?? document.body;
|
|
7675
|
+
parent.appendChild( root );
|
|
7676
|
+
}
|
|
7677
|
+
|
|
7678
|
+
}
|
|
7679
|
+
|
|
7680
|
+
LX.Footer = Footer;
|
|
7681
|
+
|
|
7170
7682
|
/**
|
|
7171
7683
|
* @class Dialog
|
|
7172
7684
|
*/
|
|
@@ -9312,7 +9824,7 @@ Object.assign(LX, {
|
|
|
9312
9824
|
//request.mimeType = "text/plain; charset=x-user-defined";
|
|
9313
9825
|
dataType = "arraybuffer";
|
|
9314
9826
|
request.mimeType = "application/octet-stream";
|
|
9315
|
-
}
|
|
9827
|
+
}
|
|
9316
9828
|
|
|
9317
9829
|
//regular case, use AJAX call
|
|
9318
9830
|
var xhr = new XMLHttpRequest();
|
|
@@ -9553,6 +10065,14 @@ Element.prototype.getComputedSize = function() {
|
|
|
9553
10065
|
}
|
|
9554
10066
|
}
|
|
9555
10067
|
|
|
10068
|
+
Element.prototype.getParentArea = function() {
|
|
10069
|
+
let parent = this.parentElement;
|
|
10070
|
+
while( parent ) {
|
|
10071
|
+
if( parent.classList.contains( "lexarea" ) ) { return parent; }
|
|
10072
|
+
parent = parent.parentElement;
|
|
10073
|
+
}
|
|
10074
|
+
}
|
|
10075
|
+
|
|
9556
10076
|
LX.UTILS = {
|
|
9557
10077
|
getTime() { return new Date().getTime() },
|
|
9558
10078
|
compareThreshold( v, p, n, t ) { return Math.abs(v - p) >= t || Math.abs(v - n) >= t },
|