lexgui 0.5.5 → 0.5.6
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/lexgui.css +166 -69
- package/build/lexgui.js +1076 -190
- package/build/lexgui.min.css +1 -1
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +1076 -190
- package/build/lexgui.module.min.js +1 -1
- package/build/utilities.css +23 -0
- package/changelog.md +15 -3
- package/demo.js +1 -1
- package/examples/all_widgets.html +13 -3
- package/examples/area_tabs.html +1 -1
- package/examples/dialogs.html +3 -3
- package/examples/timeline.html +1 -1
- package/package.json +1 -1
package/build/lexgui.js
CHANGED
|
@@ -12,7 +12,7 @@ console.warn( 'Script _build/lexgui.js_ is depracated and will be removed soon.
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
var LX = {
|
|
15
|
-
version: "0.5.
|
|
15
|
+
version: "0.5.6",
|
|
16
16
|
ready: false,
|
|
17
17
|
components: [], // Specific pre-build components
|
|
18
18
|
signals: {}, // Events and triggers
|
|
@@ -222,37 +222,141 @@ LX.getBase64Image = getBase64Image;
|
|
|
222
222
|
|
|
223
223
|
/**
|
|
224
224
|
* @method hexToRgb
|
|
225
|
-
* @description Convert a hexadecimal string to a valid RGB color
|
|
226
|
-
* @param {String}
|
|
225
|
+
* @description Convert a hexadecimal string to a valid RGB color
|
|
226
|
+
* @param {String} hex Hexadecimal color
|
|
227
227
|
*/
|
|
228
|
-
function hexToRgb(
|
|
228
|
+
function hexToRgb( hex )
|
|
229
229
|
{
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
230
|
+
const hexPattern = /^#(?:[A-Fa-f0-9]{3,4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/;
|
|
231
|
+
if( !hexPattern.test( hex ) )
|
|
232
|
+
{
|
|
233
|
+
throw( `Invalid Hex Color: ${ hex }` );
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
hex = hex.replace( /^#/, '' );
|
|
237
|
+
|
|
238
|
+
// Expand shorthand form (#RGB or #RGBA)
|
|
239
|
+
if( hex.length === 3 || hex.length === 4 )
|
|
240
|
+
{
|
|
241
|
+
hex = hex.split( '' ).map( c => c + c ).join( '' );
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const bigint = parseInt( hex, 16 );
|
|
245
|
+
|
|
246
|
+
const r = ( ( bigint >> ( hex.length === 8 ? 24 : 16 ) ) & 255 ) / 255;
|
|
247
|
+
const g = ( ( bigint >> ( hex.length === 8 ? 16 : 8 ) ) & 255 ) / 255;
|
|
248
|
+
const b = ( ( bigint >> ( hex.length === 8 ? 8 : 0 ) ) & 255 ) / 255;
|
|
249
|
+
const a = ( hex.length === 8 ? ( bigint & 255 ) : ( hex.length === 4 ? parseInt( hex.slice( -2 ), 16 ) : 255 ) ) / 255;
|
|
250
|
+
|
|
251
|
+
return { r, g, b, a };
|
|
234
252
|
}
|
|
235
253
|
|
|
236
254
|
LX.hexToRgb = hexToRgb;
|
|
237
255
|
|
|
256
|
+
/**
|
|
257
|
+
* @method hexToHsv
|
|
258
|
+
* @description Convert a hexadecimal string to HSV (0..360|0..1|0..1)
|
|
259
|
+
* @param {String} hexStr Hexadecimal color
|
|
260
|
+
*/
|
|
261
|
+
function hexToHsv( hexStr )
|
|
262
|
+
{
|
|
263
|
+
const rgb = hexToRgb( hexStr );
|
|
264
|
+
return rgbToHsv( rgb );
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
LX.hexToHsv = hexToHsv;
|
|
268
|
+
|
|
238
269
|
/**
|
|
239
270
|
* @method rgbToHex
|
|
240
|
-
* @description Convert a RGB color
|
|
241
|
-
* @param {
|
|
271
|
+
* @description Convert a RGB color to a hexadecimal string
|
|
272
|
+
* @param {Object} rgb Object containing RGB color
|
|
273
|
+
* @param {Number} scale Use 255 for 0..255 range or 1 for 0..1 range
|
|
242
274
|
*/
|
|
243
|
-
function rgbToHex( rgb )
|
|
275
|
+
function rgbToHex( rgb, scale = 255 )
|
|
244
276
|
{
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
277
|
+
const rgbArray = [ rgb.r, rgb.g, rgb.b ];
|
|
278
|
+
if( rgb.a != undefined ) rgbArray.push( rgb.a );
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
"#" +
|
|
282
|
+
rgbArray.map( c => {
|
|
283
|
+
c = Math.floor( c * scale );
|
|
284
|
+
const hex = c.toString(16);
|
|
285
|
+
return hex.length === 1 ? ( '0' + hex ) : hex;
|
|
286
|
+
}).join("")
|
|
287
|
+
);
|
|
252
288
|
}
|
|
253
289
|
|
|
254
290
|
LX.rgbToHex = rgbToHex;
|
|
255
291
|
|
|
292
|
+
/**
|
|
293
|
+
* @method rgbToCss
|
|
294
|
+
* @description Convert a RGB color (0..1) to a CSS color format
|
|
295
|
+
* @param {Object} rgb Object containing RGB color
|
|
296
|
+
*/
|
|
297
|
+
function rgbToCss( rgb )
|
|
298
|
+
{
|
|
299
|
+
return { r: Math.floor( rgb.r * 255 ), g: Math.floor( rgb.g * 255 ), b: Math.floor( rgb.b * 255 ), a: rgb.a };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
LX.rgbToCss = rgbToCss;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* @method rgbToHsv
|
|
306
|
+
* @description Convert a RGB color (0..1) array to HSV (0..360|0..1|0..1)
|
|
307
|
+
* @param {Object} rgb Array containing R, G, B
|
|
308
|
+
*/
|
|
309
|
+
function rgbToHsv( rgb )
|
|
310
|
+
{
|
|
311
|
+
let { r, g, b, a } = rgb;
|
|
312
|
+
a = a ?? 1;
|
|
313
|
+
|
|
314
|
+
const max = Math.max(r, g, b);
|
|
315
|
+
const min = Math.min(r, g, b);
|
|
316
|
+
const d = max - min;
|
|
317
|
+
let h = 0;
|
|
318
|
+
|
|
319
|
+
if (d !== 0) {
|
|
320
|
+
if (max === r) { h = ((g - b) / d) % 6 }
|
|
321
|
+
else if (max === g) { h = (b - r) / d + 2 }
|
|
322
|
+
else { h = (r - g) / d + 4 }
|
|
323
|
+
h *= 60
|
|
324
|
+
if (h < 0) { h += 360 }
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const s = max === 0 ? 0 : (d / max);
|
|
328
|
+
const v = max;
|
|
329
|
+
|
|
330
|
+
return { h, s, v, a };
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
LX.rgbToHsv = rgbToHsv;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* @method hsvToRgb
|
|
337
|
+
* @description Convert an HSV color (0..360|0..1|0..1) array to RGB (0..1|0..255)
|
|
338
|
+
* @param {Array} hsv Array containing H, S, V
|
|
339
|
+
*/
|
|
340
|
+
function hsvToRgb( hsv )
|
|
341
|
+
{
|
|
342
|
+
const { h, s, v, a } = hsv;
|
|
343
|
+
const c = v * s;
|
|
344
|
+
const x = c * (1 - Math.abs( ( (h / 60) % 2 ) - 1) )
|
|
345
|
+
const m = v - c;
|
|
346
|
+
let r = 0, g = 0, b = 0;
|
|
347
|
+
|
|
348
|
+
if( h < 60 ) { r = c; g = x; b = 0; }
|
|
349
|
+
else if ( h < 120 ) { r = x; g = c; b = 0; }
|
|
350
|
+
else if ( h < 180 ) { r = 0; g = c; b = x; }
|
|
351
|
+
else if ( h < 240 ) { r = 0; g = x; b = c; }
|
|
352
|
+
else if ( h < 300 ) { r = x; g = 0; b = c; }
|
|
353
|
+
else { r = c; g = 0; b = x; }
|
|
354
|
+
|
|
355
|
+
return { r: ( r + m ), g: ( g + m ), b: ( b + m ), a };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
LX.hsvToRgb = hsvToRgb;
|
|
359
|
+
|
|
256
360
|
/**
|
|
257
361
|
* @method measureRealWidth
|
|
258
362
|
* @description Measure the pixel width of a text
|
|
@@ -584,6 +688,42 @@ function makeCodeSnippet( code, size, options = { } )
|
|
|
584
688
|
|
|
585
689
|
LX.makeCodeSnippet = makeCodeSnippet;
|
|
586
690
|
|
|
691
|
+
/**
|
|
692
|
+
* @method makeKbd
|
|
693
|
+
* @description Kbd element to display a keyboard key.
|
|
694
|
+
* @param {Array} keys
|
|
695
|
+
* @param {String} extraClass
|
|
696
|
+
*/
|
|
697
|
+
function makeKbd( keys, extraClass = "" )
|
|
698
|
+
{
|
|
699
|
+
const specialKeys = {
|
|
700
|
+
"Ctrl": '⌃',
|
|
701
|
+
"Enter": '↩',
|
|
702
|
+
"Shift": '⇧',
|
|
703
|
+
"CapsLock": '⇪',
|
|
704
|
+
"Meta": '⌘',
|
|
705
|
+
"Option": '⌥',
|
|
706
|
+
"Alt": '⌥',
|
|
707
|
+
"Tab": '⇥',
|
|
708
|
+
"ArrowUp": '↑',
|
|
709
|
+
"ArrowDown": '↓',
|
|
710
|
+
"ArrowLeft": '←',
|
|
711
|
+
"ArrowRight": '→',
|
|
712
|
+
"Space": '␣'
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
const kbd = LX.makeContainer( ["auto", "auto"], "flex flex-row ml-auto" );
|
|
716
|
+
|
|
717
|
+
for( const k of keys )
|
|
718
|
+
{
|
|
719
|
+
LX.makeContainer( ["auto", "auto"], "self-center text-xs fg-secondary select-none", specialKeys[ k ] ?? k, kbd );
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
return kbd;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
LX.makeKbd = makeKbd;
|
|
726
|
+
|
|
587
727
|
/**
|
|
588
728
|
* @method makeIcon
|
|
589
729
|
* @description Gets an SVG element using one of LX.ICONS
|
|
@@ -722,7 +862,7 @@ function registerCommandbarEntry( name, callback )
|
|
|
722
862
|
|
|
723
863
|
LX.registerCommandbarEntry = registerCommandbarEntry;
|
|
724
864
|
|
|
725
|
-
//
|
|
865
|
+
// Utils classes
|
|
726
866
|
|
|
727
867
|
class vec2 {
|
|
728
868
|
|
|
@@ -750,6 +890,77 @@ class vec2 {
|
|
|
750
890
|
|
|
751
891
|
LX.vec2 = vec2;
|
|
752
892
|
|
|
893
|
+
class Color {
|
|
894
|
+
|
|
895
|
+
constructor( value ) {
|
|
896
|
+
|
|
897
|
+
Object.defineProperty( Color.prototype, "rgb", {
|
|
898
|
+
get: function() { return this._rgb; },
|
|
899
|
+
set: function( v ) { this._fromRGB( v ) }, enumerable: true, configurable: true
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
Object.defineProperty( Color.prototype, "hex", {
|
|
903
|
+
get: function() { return this._hex; },
|
|
904
|
+
set: function( v ) { this._fromHex( v ) }, enumerable: true, configurable: true
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
Object.defineProperty( Color.prototype, "hsv", {
|
|
908
|
+
get: function() { return this._hsv; },
|
|
909
|
+
set: function( v ) { this._fromHSV( v ) }, enumerable: true, configurable: true
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
this.set( value );
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
set( value ) {
|
|
916
|
+
|
|
917
|
+
if ( typeof value === 'string' && value.startsWith( '#' ) )
|
|
918
|
+
{
|
|
919
|
+
this._fromHex( value );
|
|
920
|
+
}
|
|
921
|
+
else if( 'r' in value && 'g' in value && 'b' in value)
|
|
922
|
+
{
|
|
923
|
+
value.a = value.a ?? 1.0;
|
|
924
|
+
this._fromRGB( value );
|
|
925
|
+
}
|
|
926
|
+
else if( 'h' in value && 's' in value && 'v' in value )
|
|
927
|
+
{
|
|
928
|
+
value.a = value.a ?? 1.0;
|
|
929
|
+
this._fromHSV( value );
|
|
930
|
+
}
|
|
931
|
+
else
|
|
932
|
+
{
|
|
933
|
+
throw( "Bad color model!", value );
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
setHSV( hsv ) { this._fromHSV( hsv ); }
|
|
938
|
+
setRGB( rgb ) { this._fromRGB( rgb ); }
|
|
939
|
+
setHex( hex ) { this._fromHex( hex ); }
|
|
940
|
+
|
|
941
|
+
_fromHex( hex ) {
|
|
942
|
+
this._fromRGB( hexToRgb( hex ) );
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
_fromRGB( rgb ) {
|
|
946
|
+
this._rgb = rgb;
|
|
947
|
+
this._hsv = rgbToHsv( rgb );
|
|
948
|
+
this._hex = rgbToHex( rgb );
|
|
949
|
+
this.css = rgbToCss( this._rgb );
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
_fromHSV( hsv ) {
|
|
953
|
+
this._hsv = hsv;
|
|
954
|
+
this._rgb = hsvToRgb( hsv );
|
|
955
|
+
this._hex = rgbToHex( this._rgb );
|
|
956
|
+
this.css = rgbToCss( this._rgb );
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
LX.Color = Color;
|
|
961
|
+
|
|
962
|
+
// Command bar creation
|
|
963
|
+
|
|
753
964
|
function _createCommandbar( root )
|
|
754
965
|
{
|
|
755
966
|
let commandbar = document.createElement( "dialog" );
|
|
@@ -1807,6 +2018,13 @@ class DropdownMenu {
|
|
|
1807
2018
|
submenuIcon.className = "fa-solid fa-angle-right fa-xs";
|
|
1808
2019
|
menuItem.appendChild( submenuIcon );
|
|
1809
2020
|
}
|
|
2021
|
+
else if( item.kbd )
|
|
2022
|
+
{
|
|
2023
|
+
item.kbd = [].concat( item.kbd );
|
|
2024
|
+
|
|
2025
|
+
const kbd = LX.makeKbd( item.kbd );
|
|
2026
|
+
menuItem.appendChild( kbd );
|
|
2027
|
+
}
|
|
1810
2028
|
|
|
1811
2029
|
if( item.icon )
|
|
1812
2030
|
{
|
|
@@ -1826,57 +2044,508 @@ class DropdownMenu {
|
|
|
1826
2044
|
const input = checkbox.root.querySelector( "input" );
|
|
1827
2045
|
menuItem.prepend( input );
|
|
1828
2046
|
|
|
1829
|
-
menuItem.addEventListener( "click", (e) => {
|
|
1830
|
-
if( e.target.type == "checkbox" ) return;
|
|
1831
|
-
input.checked = !input.checked;
|
|
1832
|
-
checkbox.set( input.checked );
|
|
1833
|
-
} );
|
|
1834
|
-
}
|
|
1835
|
-
else
|
|
1836
|
-
{
|
|
1837
|
-
menuItem.addEventListener( "click", () => {
|
|
1838
|
-
const f = item[ 'callback' ];
|
|
1839
|
-
if( f )
|
|
1840
|
-
{
|
|
1841
|
-
f.call( this, key, menuItem );
|
|
1842
|
-
}
|
|
1843
|
-
this.destroy();
|
|
1844
|
-
} );
|
|
1845
|
-
}
|
|
2047
|
+
menuItem.addEventListener( "click", (e) => {
|
|
2048
|
+
if( e.target.type == "checkbox" ) return;
|
|
2049
|
+
input.checked = !input.checked;
|
|
2050
|
+
checkbox.set( input.checked );
|
|
2051
|
+
} );
|
|
2052
|
+
}
|
|
2053
|
+
else
|
|
2054
|
+
{
|
|
2055
|
+
menuItem.addEventListener( "click", () => {
|
|
2056
|
+
const f = item[ 'callback' ];
|
|
2057
|
+
if( f )
|
|
2058
|
+
{
|
|
2059
|
+
f.call( this, key, menuItem );
|
|
2060
|
+
}
|
|
2061
|
+
this.destroy();
|
|
2062
|
+
} );
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
menuItem.addEventListener("mouseover", e => {
|
|
2066
|
+
|
|
2067
|
+
let path = menuItem.id;
|
|
2068
|
+
let p = parentDom;
|
|
2069
|
+
|
|
2070
|
+
while( p )
|
|
2071
|
+
{
|
|
2072
|
+
path += "/" + p.id;
|
|
2073
|
+
p = p.currentParent?.parentElement;
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
LX.root.querySelectorAll( ".lexdropdownmenu" ).forEach( m => {
|
|
2077
|
+
if( !path.includes( m.id ) )
|
|
2078
|
+
{
|
|
2079
|
+
m.currentParent.built = false;
|
|
2080
|
+
m.remove();
|
|
2081
|
+
}
|
|
2082
|
+
} );
|
|
2083
|
+
|
|
2084
|
+
if( item.submenu )
|
|
2085
|
+
{
|
|
2086
|
+
if( menuItem.built )
|
|
2087
|
+
{
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
menuItem.built = true;
|
|
2091
|
+
this._create( item.submenu, menuItem );
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
e.stopPropagation();
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
_adjustPosition() {
|
|
2100
|
+
|
|
2101
|
+
const position = [ 0, 0 ];
|
|
2102
|
+
|
|
2103
|
+
// Place menu using trigger position and user options
|
|
2104
|
+
{
|
|
2105
|
+
const rect = this._trigger.getBoundingClientRect();
|
|
2106
|
+
|
|
2107
|
+
let alignWidth = true;
|
|
2108
|
+
|
|
2109
|
+
switch( this.side )
|
|
2110
|
+
{
|
|
2111
|
+
case "left":
|
|
2112
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
2113
|
+
alignWidth = false;
|
|
2114
|
+
break;
|
|
2115
|
+
case "right":
|
|
2116
|
+
position[ 0 ] += ( rect.x + rect.width );
|
|
2117
|
+
alignWidth = false;
|
|
2118
|
+
break;
|
|
2119
|
+
case "top":
|
|
2120
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
2121
|
+
alignWidth = true;
|
|
2122
|
+
break;
|
|
2123
|
+
case "bottom":
|
|
2124
|
+
position[ 1 ] += ( rect.y + rect.height );
|
|
2125
|
+
alignWidth = true;
|
|
2126
|
+
break;
|
|
2127
|
+
default:
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
switch( this.align )
|
|
2132
|
+
{
|
|
2133
|
+
case "start":
|
|
2134
|
+
if( alignWidth ) { position[ 0 ] += rect.x; }
|
|
2135
|
+
else { position[ 1 ] += rect.y; }
|
|
2136
|
+
break;
|
|
2137
|
+
case "center":
|
|
2138
|
+
if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - this.root.offsetWidth * 0.5; }
|
|
2139
|
+
else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - this.root.offsetHeight * 0.5; }
|
|
2140
|
+
break;
|
|
2141
|
+
case "end":
|
|
2142
|
+
if( alignWidth ) { position[ 0 ] += rect.x - this.root.offsetWidth + rect.width; }
|
|
2143
|
+
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
2144
|
+
break;
|
|
2145
|
+
default:
|
|
2146
|
+
break;
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
if( this.avoidCollisions )
|
|
2151
|
+
{
|
|
2152
|
+
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - this.root.offsetWidth - this._windowPadding );
|
|
2153
|
+
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - this.root.offsetHeight - this._windowPadding );
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
this.root.style.left = `${ position[ 0 ] }px`;
|
|
2157
|
+
this.root.style.top = `${ position[ 1 ] }px`;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
_addSeparator( parent ) {
|
|
2161
|
+
const separator = document.createElement('div');
|
|
2162
|
+
separator.className = "separator";
|
|
2163
|
+
parent = parent ?? this.root;
|
|
2164
|
+
parent.appendChild( separator );
|
|
2165
|
+
}
|
|
2166
|
+
};
|
|
2167
|
+
|
|
2168
|
+
LX.DropdownMenu = DropdownMenu;
|
|
2169
|
+
|
|
2170
|
+
/**
|
|
2171
|
+
* @class ColorPicker
|
|
2172
|
+
*/
|
|
2173
|
+
|
|
2174
|
+
class ColorPicker {
|
|
2175
|
+
|
|
2176
|
+
static currentPicker = false;
|
|
2177
|
+
|
|
2178
|
+
constructor( hexValue, trigger, options = {} ) {
|
|
2179
|
+
|
|
2180
|
+
console.assert( trigger, "ColorPicker needs a DOM element as trigger!" );
|
|
2181
|
+
|
|
2182
|
+
this._windowPadding = 4;
|
|
2183
|
+
this.side = options.side ?? "bottom";
|
|
2184
|
+
this.align = options.align ?? "center";
|
|
2185
|
+
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
2186
|
+
this.colorModel = options.colorModel ?? "Hex";
|
|
2187
|
+
this.useAlpha = options.useAlpha ?? false;
|
|
2188
|
+
this.callback = options.onChange;
|
|
2189
|
+
|
|
2190
|
+
if( !this.callback )
|
|
2191
|
+
{
|
|
2192
|
+
console.warn( "Define a callback in _options.onChange_ to allow getting new Color values!" );
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
if( ColorPicker.currentPicker )
|
|
2196
|
+
{
|
|
2197
|
+
ColorPicker.currentPicker.destroy();
|
|
2198
|
+
return;
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
this._trigger = trigger;
|
|
2202
|
+
trigger.classList.add( "triggered" );
|
|
2203
|
+
trigger.picker = this;
|
|
2204
|
+
|
|
2205
|
+
this.root = document.createElement( "div" );
|
|
2206
|
+
this.root.tabIndex = "1";
|
|
2207
|
+
this.root.className = "lexcolorpicker";
|
|
2208
|
+
this.root.dataset["side"] = this.side;
|
|
2209
|
+
LX.root.appendChild( this.root );
|
|
2210
|
+
|
|
2211
|
+
this.root.addEventListener( "keydown", (e) => {
|
|
2212
|
+
if( e.key == "Escape" )
|
|
2213
|
+
{
|
|
2214
|
+
e.preventDefault();
|
|
2215
|
+
e.stopPropagation();
|
|
2216
|
+
this.destroy();
|
|
2217
|
+
}
|
|
2218
|
+
} )
|
|
2219
|
+
|
|
2220
|
+
ColorPicker.currentPicker = this;
|
|
2221
|
+
|
|
2222
|
+
this.markerHalfSize = 8;
|
|
2223
|
+
this.markerSize = this.markerHalfSize * 2;
|
|
2224
|
+
this.currentColor = new Color( hexValue );
|
|
2225
|
+
|
|
2226
|
+
const hueColor = new Color( { h: this.currentColor.hsv.h, s: 1, v: 1 } );
|
|
2227
|
+
|
|
2228
|
+
// Intensity, Sat
|
|
2229
|
+
this.colorPickerBackground = document.createElement( 'div' );
|
|
2230
|
+
this.colorPickerBackground.className = "lexcolorpickerbg";
|
|
2231
|
+
this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2232
|
+
this.root.appendChild( this.colorPickerBackground );
|
|
2233
|
+
|
|
2234
|
+
this.intSatMarker = document.createElement( 'div' );
|
|
2235
|
+
this.intSatMarker.className = "lexcolormarker";
|
|
2236
|
+
this.intSatMarker.style.backgroundColor = this.currentColor.hex;
|
|
2237
|
+
this.colorPickerBackground.appendChild( this.intSatMarker );
|
|
2238
|
+
|
|
2239
|
+
doAsync( this._svToPosition.bind( this, this.currentColor.hsv.s, this.currentColor.hsv.v ) );
|
|
2240
|
+
|
|
2241
|
+
let innerMouseDown = e => {
|
|
2242
|
+
var doc = this.root.ownerDocument;
|
|
2243
|
+
doc.addEventListener( 'mousemove', innerMouseMove );
|
|
2244
|
+
doc.addEventListener( 'mouseup', innerMouseUp );
|
|
2245
|
+
document.body.classList.add( 'noevents' );
|
|
2246
|
+
e.stopImmediatePropagation();
|
|
2247
|
+
e.stopPropagation();
|
|
2248
|
+
|
|
2249
|
+
const currentLeft = ( e.offsetX - this.markerHalfSize );
|
|
2250
|
+
this.intSatMarker.style.left = currentLeft + "px";
|
|
2251
|
+
const currentTop = ( e.offsetY - this.markerHalfSize );
|
|
2252
|
+
this.intSatMarker.style.top = currentTop + "px";
|
|
2253
|
+
this._positionToSv( currentLeft, currentTop );
|
|
2254
|
+
this._updateColorValue();
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
let innerMouseMove = e => {
|
|
2258
|
+
const dX = e.movementX;
|
|
2259
|
+
const dY = e.movementY;
|
|
2260
|
+
|
|
2261
|
+
const rect = this.colorPickerBackground.getBoundingClientRect();
|
|
2262
|
+
const mouseX = e.offsetX - rect.x;
|
|
2263
|
+
const mouseY = e.offsetY - rect.y;
|
|
2264
|
+
|
|
2265
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.colorPickerBackground.offsetWidth || dX > 0 ) )
|
|
2266
|
+
{
|
|
2267
|
+
this.intSatMarker.style.left = LX.clamp( parseInt( this.intSatMarker.style.left ) + dX, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize ) + "px";
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
if ( dY != 0 && ( mouseY >= 0 || dY < 0 ) && ( mouseY < this.colorPickerBackground.offsetHeight || dY > 0 ) )
|
|
2271
|
+
{
|
|
2272
|
+
this.intSatMarker.style.top = LX.clamp( parseInt( this.intSatMarker.style.top ) + dY, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize ) + "px";
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
this._positionToSv( parseInt( this.intSatMarker.style.left ), parseInt( this.intSatMarker.style.top ) );
|
|
2276
|
+
this._updateColorValue();
|
|
2277
|
+
|
|
2278
|
+
e.stopPropagation();
|
|
2279
|
+
e.preventDefault();
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
let innerMouseUp = e => {
|
|
2283
|
+
var doc = this.root.ownerDocument;
|
|
2284
|
+
doc.removeEventListener( 'mousemove', innerMouseMove );
|
|
2285
|
+
doc.removeEventListener( 'mouseup', innerMouseUp );
|
|
2286
|
+
document.body.classList.remove( 'noevents' );
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
this.colorPickerBackground.addEventListener( "mousedown", innerMouseDown );
|
|
2290
|
+
|
|
2291
|
+
const hueAlphaContainer = LX.makeContainer( ["100%", "auto"], "flex flex-row gap-1 items-center", "", this.root );
|
|
2292
|
+
|
|
2293
|
+
if( window.EyeDropper )
|
|
2294
|
+
{
|
|
2295
|
+
hueAlphaContainer.appendChild( new Button(null, "eyedrop", async () => {
|
|
2296
|
+
const eyeDropper = new EyeDropper()
|
|
2297
|
+
try {
|
|
2298
|
+
const result = await eyeDropper.open();
|
|
2299
|
+
this.fromHexColor( result.sRGBHex );
|
|
2300
|
+
} catch ( err ) {
|
|
2301
|
+
// console.error("EyeDropper cancelled or failed: ", err)
|
|
2302
|
+
}
|
|
2303
|
+
}, { icon: "eye-dropper", buttonClass: "bg-none", title: "Sample Color" }).root );
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
const innerHueAlpha = LX.makeContainer( ["100%", "100%"], "flex flex-col gap-2", "", hueAlphaContainer );
|
|
2307
|
+
|
|
2308
|
+
// Hue
|
|
2309
|
+
this.colorPickerTracker = document.createElement( 'div' );
|
|
2310
|
+
this.colorPickerTracker.className = "lexhuetracker";
|
|
2311
|
+
innerHueAlpha.appendChild( this.colorPickerTracker );
|
|
2312
|
+
|
|
2313
|
+
this.hueMarker = document.createElement( 'div' );
|
|
2314
|
+
this.hueMarker.className = "lexcolormarker";
|
|
2315
|
+
this.hueMarker.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2316
|
+
this.colorPickerTracker.appendChild( this.hueMarker );
|
|
2317
|
+
|
|
2318
|
+
doAsync( () => {
|
|
2319
|
+
const hueLeft = LX.remapRange( this.currentColor.hsv.h, 0, 360, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2320
|
+
this.hueMarker.style.left = hueLeft + "px";
|
|
2321
|
+
} );
|
|
2322
|
+
|
|
2323
|
+
const _fromHueX = ( hueX ) => {
|
|
2324
|
+
this.hueMarker.style.left = hueX + "px";
|
|
2325
|
+
this.currentColor.hsv.h = LX.remapRange( hueX, 0, this.colorPickerTracker.offsetWidth - this.markerSize, 0, 360 );
|
|
2326
|
+
|
|
2327
|
+
const hueColor = new Color( { h: this.currentColor.hsv.h, s: 1, v: 1 } );
|
|
2328
|
+
this.hueMarker.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2329
|
+
this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2330
|
+
this._updateColorValue();
|
|
2331
|
+
};
|
|
2332
|
+
|
|
2333
|
+
let innerMouseDownHue = e => {
|
|
2334
|
+
const doc = this.root.ownerDocument;
|
|
2335
|
+
doc.addEventListener( 'mousemove', innerMouseMoveHue );
|
|
2336
|
+
doc.addEventListener( 'mouseup', innerMouseUpHue );
|
|
2337
|
+
document.body.classList.add( 'noevents' );
|
|
2338
|
+
e.stopImmediatePropagation();
|
|
2339
|
+
e.stopPropagation();
|
|
2340
|
+
|
|
2341
|
+
const hueX = clamp( e.offsetX - this.markerHalfSize, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2342
|
+
_fromHueX( hueX );
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
let innerMouseMoveHue = e => {
|
|
2346
|
+
let dX = e.movementX;
|
|
2347
|
+
|
|
2348
|
+
const rect = this.colorPickerTracker.getBoundingClientRect();
|
|
2349
|
+
const mouseX = e.offsetX - rect.x;
|
|
2350
|
+
|
|
2351
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.colorPickerTracker.offsetWidth || dX > 0 ) )
|
|
2352
|
+
{
|
|
2353
|
+
const hueX = LX.clamp( parseInt( this.hueMarker.style.left ) + dX, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2354
|
+
_fromHueX( hueX )
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
e.stopPropagation();
|
|
2358
|
+
e.preventDefault();
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
let innerMouseUpHue = e => {
|
|
2362
|
+
var doc = this.root.ownerDocument;
|
|
2363
|
+
doc.removeEventListener( 'mousemove', innerMouseMoveHue );
|
|
2364
|
+
doc.removeEventListener( 'mouseup', innerMouseUpHue );
|
|
2365
|
+
document.body.classList.remove( 'noevents' );
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
this.colorPickerTracker.addEventListener( "mousedown", innerMouseDownHue );
|
|
2369
|
+
|
|
2370
|
+
// Alpha
|
|
2371
|
+
if( this.useAlpha )
|
|
2372
|
+
{
|
|
2373
|
+
this.alphaTracker = document.createElement( 'div' );
|
|
2374
|
+
this.alphaTracker.className = "lexalphatracker";
|
|
2375
|
+
this.alphaTracker.style.color = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b })`;
|
|
2376
|
+
innerHueAlpha.appendChild( this.alphaTracker );
|
|
2377
|
+
|
|
2378
|
+
this.alphaMarker = document.createElement( 'div' );
|
|
2379
|
+
this.alphaMarker.className = "lexcolormarker";
|
|
2380
|
+
this.alphaMarker.style.backgroundColor = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2381
|
+
this.alphaTracker.appendChild( this.alphaMarker );
|
|
2382
|
+
|
|
2383
|
+
doAsync( () => {
|
|
2384
|
+
const alphaLeft = LX.remapRange( this.currentColor.hsv.a, 0, 1, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2385
|
+
this.alphaMarker.style.left = alphaLeft + "px";
|
|
2386
|
+
} );
|
|
2387
|
+
|
|
2388
|
+
const _fromAlphaX = ( alphaX ) => {
|
|
2389
|
+
this.alphaMarker.style.left = alphaX + "px";
|
|
2390
|
+
this.currentColor.hsv.a = LX.remapRange( alphaX, 0, this.alphaTracker.offsetWidth - this.markerSize, 0, 1 );
|
|
2391
|
+
this._updateColorValue();
|
|
2392
|
+
// Update alpha marker once the color is updated
|
|
2393
|
+
this.alphaMarker.style.backgroundColor = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2394
|
+
};
|
|
2395
|
+
|
|
2396
|
+
let innerMouseDownAlpha = e => {
|
|
2397
|
+
const doc = this.root.ownerDocument;
|
|
2398
|
+
doc.addEventListener( 'mousemove', innerMouseMoveAlpha );
|
|
2399
|
+
doc.addEventListener( 'mouseup', innerMouseUpAlpha );
|
|
2400
|
+
document.body.classList.add( 'noevents' );
|
|
2401
|
+
e.stopImmediatePropagation();
|
|
2402
|
+
e.stopPropagation();
|
|
2403
|
+
const alphaX = clamp( e.offsetX - this.markerHalfSize, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2404
|
+
_fromAlphaX( alphaX );
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
let innerMouseMoveAlpha = e => {
|
|
2408
|
+
let dX = e.movementX;
|
|
2409
|
+
|
|
2410
|
+
const rect = this.alphaTracker.getBoundingClientRect();
|
|
2411
|
+
const mouseX = e.offsetX - rect.x;
|
|
2412
|
+
|
|
2413
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.alphaTracker.offsetWidth || dX > 0 ) )
|
|
2414
|
+
{
|
|
2415
|
+
const alphaX = LX.clamp( parseInt( this.alphaMarker.style.left ) + dX, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2416
|
+
_fromAlphaX( alphaX );
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
e.stopPropagation();
|
|
2420
|
+
e.preventDefault();
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
let innerMouseUpAlpha = e => {
|
|
2424
|
+
var doc = this.root.ownerDocument;
|
|
2425
|
+
doc.removeEventListener( 'mousemove', innerMouseMoveAlpha );
|
|
2426
|
+
doc.removeEventListener( 'mouseup', innerMouseUpAlpha );
|
|
2427
|
+
document.body.classList.remove( 'noevents' );
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
this.alphaTracker.addEventListener( "mousedown", innerMouseDownAlpha );
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
// Info display
|
|
2434
|
+
const colorLabel = LX.makeContainer( ["100%", "auto"], "flex flex-row gap-1", "", this.root );
|
|
2435
|
+
|
|
2436
|
+
colorLabel.appendChild( new Select( null, [ "CSS", "Hex", "HSV", "RGB" ], this.colorModel, v => {
|
|
2437
|
+
this.colorModel = v;
|
|
2438
|
+
this._updateColorValue( null, true );
|
|
2439
|
+
} ).root );
|
|
2440
|
+
|
|
2441
|
+
this.labelWidget = new TextInput( null, "", null, { inputClass: "bg-none", fit: true, disabled: true } );
|
|
2442
|
+
colorLabel.appendChild( this.labelWidget.root );
|
|
2443
|
+
|
|
2444
|
+
colorLabel.appendChild( new Button(null, "eyedrop", async () => {
|
|
2445
|
+
navigator.clipboard.writeText( this.labelWidget.value() );
|
|
2446
|
+
}, { icon: "copy", buttonClass: "bg-none", className: "ml-auto", title: "Copy" }).root );
|
|
2447
|
+
|
|
2448
|
+
this._updateColorValue( hexValue, true );
|
|
2449
|
+
|
|
2450
|
+
doAsync( () => {
|
|
2451
|
+
this._adjustPosition();
|
|
2452
|
+
|
|
2453
|
+
this.root.focus();
|
|
2454
|
+
|
|
2455
|
+
this._onClick = e => {
|
|
2456
|
+
if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
|
|
2457
|
+
{
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
this.destroy();
|
|
2461
|
+
};
|
|
2462
|
+
|
|
2463
|
+
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
2464
|
+
document.body.addEventListener( "focusin", this._onClick, true );
|
|
2465
|
+
}, 10 );
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
fromHexColor( hexColor ) {
|
|
2469
|
+
|
|
2470
|
+
this.currentColor.setHex( hexColor );
|
|
2471
|
+
|
|
2472
|
+
// Decompose into HSV
|
|
2473
|
+
const { h, s, v } = this.currentColor.hsv;
|
|
2474
|
+
this._svToPosition( s, v );
|
|
2475
|
+
|
|
2476
|
+
const hueColor = new Color( { h, s: 1, v: 1 } );
|
|
2477
|
+
this.hueMarker.style.backgroundColor = this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2478
|
+
this.hueMarker.style.left = LX.remapRange( h, 0, 360, -this.markerHalfSize, this.colorPickerTracker.offsetWidth - this.markerHalfSize ) + "px";
|
|
2479
|
+
|
|
2480
|
+
this._updateColorValue( hexColor );
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
destroy() {
|
|
2484
|
+
|
|
2485
|
+
this._trigger.classList.remove( "triggered" );
|
|
2486
|
+
|
|
2487
|
+
delete this._trigger.picker;
|
|
2488
|
+
|
|
2489
|
+
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
2490
|
+
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
2491
|
+
|
|
2492
|
+
LX.root.querySelectorAll( ".lexcolorpicker" ).forEach( m => { m.remove(); } );
|
|
2493
|
+
|
|
2494
|
+
ColorPicker.currentPicker = null;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
_svToPosition( s, v ) {
|
|
2498
|
+
this.intSatMarker.style.left = `${ LX.remapRange( s, 0, 1, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize ) }px`;
|
|
2499
|
+
this.intSatMarker.style.top = `${ LX.remapRange( 1 - v, 0, 1, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize ) }px`
|
|
2500
|
+
};
|
|
2501
|
+
|
|
2502
|
+
_positionToSv( left, top ) {
|
|
2503
|
+
this.currentColor.hsv.s = LX.remapRange( left, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize, 0, 1 );
|
|
2504
|
+
this.currentColor.hsv.v = 1 - LX.remapRange( top, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize, 0, 1 );
|
|
2505
|
+
};
|
|
2506
|
+
|
|
2507
|
+
_updateColorValue( newHexValue, skipCallback = false ) {
|
|
1846
2508
|
|
|
1847
|
-
|
|
2509
|
+
this.currentColor.set( newHexValue ?? this.currentColor.hsv );
|
|
1848
2510
|
|
|
1849
|
-
|
|
1850
|
-
|
|
2511
|
+
if( this.callback && !skipCallback )
|
|
2512
|
+
{
|
|
2513
|
+
this.callback( this.currentColor );
|
|
2514
|
+
}
|
|
1851
2515
|
|
|
1852
|
-
|
|
1853
|
-
{
|
|
1854
|
-
path += "/" + p.id;
|
|
1855
|
-
p = p.currentParent?.parentElement;
|
|
1856
|
-
}
|
|
2516
|
+
this.intSatMarker.style.backgroundColor = this.currentColor.hex;
|
|
1857
2517
|
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
m.remove();
|
|
1863
|
-
}
|
|
1864
|
-
} );
|
|
2518
|
+
if( this.useAlpha )
|
|
2519
|
+
{
|
|
2520
|
+
this.alphaTracker.style.color = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2521
|
+
}
|
|
1865
2522
|
|
|
1866
|
-
|
|
1867
|
-
{
|
|
1868
|
-
if( menuItem.built )
|
|
1869
|
-
{
|
|
1870
|
-
return;
|
|
1871
|
-
}
|
|
1872
|
-
menuItem.built = true;
|
|
1873
|
-
this._create( item.submenu, menuItem );
|
|
1874
|
-
}
|
|
2523
|
+
const toFixed = ( s, n = 2) => { return s.toFixed( n ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' ) };
|
|
1875
2524
|
|
|
1876
|
-
|
|
1877
|
-
|
|
2525
|
+
if( this.colorModel == "CSS" )
|
|
2526
|
+
{
|
|
2527
|
+
const { r, g, b, a } = this.currentColor.css;
|
|
2528
|
+
this.labelWidget.set( `rgba(${ r },${ g },${ b }${ this.useAlpha ? ',' + toFixed( a ) : '' })` );
|
|
1878
2529
|
}
|
|
1879
|
-
|
|
2530
|
+
else if( this.colorModel == "Hex" )
|
|
2531
|
+
{
|
|
2532
|
+
this.labelWidget.set( ( this.useAlpha ? this.currentColor.hex : this.currentColor.hex.substr( 0, 7 ) ).toUpperCase() );
|
|
2533
|
+
}
|
|
2534
|
+
else if( this.colorModel == "HSV" )
|
|
2535
|
+
{
|
|
2536
|
+
const { h, s, v, a } = this.currentColor.hsv;
|
|
2537
|
+
const components = [ Math.floor( h ) + 'º', Math.floor( s * 100 ) + '%', Math.floor( v * 100 ) + '%' ];
|
|
2538
|
+
if( this.useAlpha ) components.push( toFixed( a ) );
|
|
2539
|
+
this.labelWidget.set( components.join( ' ' ) );
|
|
2540
|
+
}
|
|
2541
|
+
else // RGB
|
|
2542
|
+
{
|
|
2543
|
+
const { r, g, b, a } = this.currentColor.rgb;
|
|
2544
|
+
const components = [ toFixed( r ), toFixed( g ), toFixed( b ) ];
|
|
2545
|
+
if( this.useAlpha ) components.push( toFixed( a ) );
|
|
2546
|
+
this.labelWidget.set( components.join( ' ' ) );
|
|
2547
|
+
}
|
|
2548
|
+
};
|
|
1880
2549
|
|
|
1881
2550
|
_adjustPosition() {
|
|
1882
2551
|
|
|
@@ -1938,16 +2607,9 @@ class DropdownMenu {
|
|
|
1938
2607
|
this.root.style.left = `${ position[ 0 ] }px`;
|
|
1939
2608
|
this.root.style.top = `${ position[ 1 ] }px`;
|
|
1940
2609
|
}
|
|
1941
|
-
|
|
1942
|
-
_addSeparator( parent ) {
|
|
1943
|
-
const separator = document.createElement('div');
|
|
1944
|
-
separator.className = "separator";
|
|
1945
|
-
parent = parent ?? this.root;
|
|
1946
|
-
parent.appendChild( separator );
|
|
1947
|
-
}
|
|
1948
2610
|
};
|
|
1949
2611
|
|
|
1950
|
-
LX.
|
|
2612
|
+
LX.ColorPicker = ColorPicker;
|
|
1951
2613
|
|
|
1952
2614
|
class Area {
|
|
1953
2615
|
|
|
@@ -3810,57 +4472,14 @@ class Menubar {
|
|
|
3810
4472
|
|
|
3811
4473
|
for( let i = 0; i < buttons.length; ++i )
|
|
3812
4474
|
{
|
|
3813
|
-
|
|
3814
|
-
let button = document.createElement( "label" );
|
|
4475
|
+
const data = buttons[ i ];
|
|
3815
4476
|
const title = data.title;
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
button.title = title ?? "";
|
|
3819
|
-
this.buttonContainer.appendChild( button );
|
|
3820
|
-
|
|
3821
|
-
const icon = document.createElement( "a" );
|
|
3822
|
-
icon.className = data.icon + " lexicon";
|
|
3823
|
-
button.appendChild( icon );
|
|
3824
|
-
|
|
3825
|
-
let trigger = icon;
|
|
3826
|
-
|
|
3827
|
-
if( data.swap )
|
|
3828
|
-
{
|
|
3829
|
-
button.classList.add( "swap" );
|
|
3830
|
-
icon.classList.add( "swap-off" );
|
|
3831
|
-
|
|
3832
|
-
const input = document.createElement( "input" );
|
|
3833
|
-
input.type = "checkbox";
|
|
3834
|
-
button.prepend( input );
|
|
3835
|
-
trigger = input;
|
|
3836
|
-
|
|
3837
|
-
const swapIcon = document.createElement( "a" );
|
|
3838
|
-
swapIcon.className = data.swap + " swap-on lexicon";
|
|
3839
|
-
button.appendChild( swapIcon );
|
|
3840
|
-
|
|
3841
|
-
button.swap = function() {
|
|
3842
|
-
const swapInput = this.querySelector( "input" );
|
|
3843
|
-
swapInput.checked = !swapInput.checked;
|
|
3844
|
-
};
|
|
3845
|
-
|
|
3846
|
-
// Set if swap has to be performed
|
|
3847
|
-
button.setState = function( v ) {
|
|
3848
|
-
const swapInput = this.querySelector( "input" );
|
|
3849
|
-
swapInput.checked = v;
|
|
3850
|
-
};
|
|
3851
|
-
}
|
|
3852
|
-
|
|
3853
|
-
trigger.addEventListener("click", e => {
|
|
3854
|
-
if( data.callback && !disabled )
|
|
3855
|
-
{
|
|
3856
|
-
const swapInput = button.querySelector( "input" );
|
|
3857
|
-
data.callback.call( this, e, swapInput?.checked );
|
|
3858
|
-
}
|
|
3859
|
-
});
|
|
4477
|
+
const button = new Button( title, "", data.callback, { title, buttonClass: "bg-none", disabled: data.disabled, icon: data.icon, hideName: true, swap: data.swap } )
|
|
4478
|
+
this.buttonContainer.appendChild( button.root );
|
|
3860
4479
|
|
|
3861
4480
|
if( title )
|
|
3862
4481
|
{
|
|
3863
|
-
this.buttons[ title ] = button;
|
|
4482
|
+
this.buttons[ title ] = button.root;
|
|
3864
4483
|
}
|
|
3865
4484
|
}
|
|
3866
4485
|
}
|
|
@@ -4563,14 +5182,15 @@ class Widget {
|
|
|
4563
5182
|
static SEPARATOR = 26;
|
|
4564
5183
|
static KNOB = 27;
|
|
4565
5184
|
static SIZE = 28;
|
|
4566
|
-
static
|
|
4567
|
-
static
|
|
4568
|
-
static
|
|
4569
|
-
static
|
|
4570
|
-
static
|
|
4571
|
-
static
|
|
4572
|
-
static
|
|
4573
|
-
static
|
|
5185
|
+
static OTP = 29;
|
|
5186
|
+
static PAD = 30;
|
|
5187
|
+
static FORM = 31;
|
|
5188
|
+
static DIAL = 32;
|
|
5189
|
+
static COUNTER = 33;
|
|
5190
|
+
static TABLE = 34;
|
|
5191
|
+
static TABS = 35;
|
|
5192
|
+
static LABEL = 36;
|
|
5193
|
+
static BLANK = 37;
|
|
4574
5194
|
|
|
4575
5195
|
static NO_CONTEXT_TYPES = [
|
|
4576
5196
|
Widget.BUTTON,
|
|
@@ -5815,40 +6435,17 @@ class Button extends Widget {
|
|
|
5815
6435
|
super( Widget.BUTTON, name, null, options );
|
|
5816
6436
|
|
|
5817
6437
|
this.onGetValue = () => {
|
|
5818
|
-
return wValue.
|
|
6438
|
+
return wValue.querySelector( "input" )?.checked;
|
|
5819
6439
|
};
|
|
5820
6440
|
|
|
5821
6441
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
5822
6442
|
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
if( options.icon )
|
|
5826
|
-
{
|
|
5827
|
-
let icon = null;
|
|
5828
|
-
|
|
5829
|
-
// @legacy
|
|
5830
|
-
if( options.icon.includes( "fa-" ) )
|
|
5831
|
-
{
|
|
5832
|
-
icon = document.createElement( 'a' );
|
|
5833
|
-
icon.className = options.icon;
|
|
5834
|
-
}
|
|
5835
|
-
else
|
|
5836
|
-
{
|
|
5837
|
-
icon = LX.makeIcon( options.icon );
|
|
5838
|
-
}
|
|
5839
|
-
|
|
5840
|
-
wValue.prepend( icon );
|
|
5841
|
-
}
|
|
5842
|
-
else if( options.img )
|
|
6443
|
+
if( !( options.swap ?? false ) )
|
|
5843
6444
|
{
|
|
5844
|
-
|
|
5845
|
-
img.src = options.img;
|
|
5846
|
-
wValue.prepend( img );
|
|
5847
|
-
}
|
|
5848
|
-
else
|
|
5849
|
-
{
|
|
5850
|
-
wValue.innerHTML = `<span>${ ( newValue || "" ) }</span>`;
|
|
6445
|
+
return;
|
|
5851
6446
|
}
|
|
6447
|
+
|
|
6448
|
+
this.root.setState( newValue, skipCallback );
|
|
5852
6449
|
};
|
|
5853
6450
|
|
|
5854
6451
|
this.onResize = ( rect ) => {
|
|
@@ -5872,25 +6469,88 @@ class Button extends Widget {
|
|
|
5872
6469
|
wValue.classList.add( "selected" );
|
|
5873
6470
|
}
|
|
5874
6471
|
|
|
5875
|
-
|
|
6472
|
+
if( options.icon )
|
|
6473
|
+
{
|
|
6474
|
+
let icon = null;
|
|
6475
|
+
|
|
6476
|
+
// @legacy
|
|
6477
|
+
if( options.icon.includes( "fa-" ) )
|
|
6478
|
+
{
|
|
6479
|
+
icon = document.createElement( 'a' );
|
|
6480
|
+
icon.className = options.icon + " lexicon";
|
|
6481
|
+
}
|
|
6482
|
+
else
|
|
6483
|
+
{
|
|
6484
|
+
icon = LX.makeIcon( options.icon );
|
|
6485
|
+
}
|
|
6486
|
+
|
|
6487
|
+
wValue.prepend( icon );
|
|
6488
|
+
}
|
|
6489
|
+
else if( options.img )
|
|
6490
|
+
{
|
|
6491
|
+
let img = document.createElement( 'img' );
|
|
6492
|
+
img.src = options.img;
|
|
6493
|
+
wValue.prepend( img );
|
|
6494
|
+
}
|
|
6495
|
+
else
|
|
6496
|
+
{
|
|
6497
|
+
wValue.innerHTML = `<span>${ ( value || "" ) }</span>`;
|
|
6498
|
+
}
|
|
5876
6499
|
|
|
5877
6500
|
if( options.disabled )
|
|
5878
6501
|
{
|
|
5879
6502
|
wValue.setAttribute( "disabled", true );
|
|
5880
6503
|
}
|
|
5881
6504
|
|
|
5882
|
-
|
|
6505
|
+
let trigger = wValue;
|
|
6506
|
+
|
|
6507
|
+
if( options.swap )
|
|
6508
|
+
{
|
|
6509
|
+
wValue.classList.add( "swap" );
|
|
6510
|
+
wValue.querySelector( "a" ).classList.add( "swap-off" );
|
|
6511
|
+
|
|
6512
|
+
const input = document.createElement( "input" );
|
|
6513
|
+
input.type = "checkbox";
|
|
6514
|
+
wValue.prepend( input );
|
|
6515
|
+
// trigger = input;
|
|
6516
|
+
|
|
6517
|
+
const swapIcon = document.createElement( "a" );
|
|
6518
|
+
swapIcon.className = options.swap + " swap-on lexicon";
|
|
6519
|
+
wValue.appendChild( swapIcon );
|
|
6520
|
+
|
|
6521
|
+
this.root.swap = function( skipCallback ) {
|
|
6522
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6523
|
+
swapInput.checked = !swapInput.checked;
|
|
6524
|
+
if( !skipCallback )
|
|
6525
|
+
{
|
|
6526
|
+
trigger.click();
|
|
6527
|
+
}
|
|
6528
|
+
};
|
|
6529
|
+
|
|
6530
|
+
// Set if swap has to be performed
|
|
6531
|
+
this.root.setState = function( v, skipCallback ) {
|
|
6532
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6533
|
+
swapInput.checked = v;
|
|
6534
|
+
if( !skipCallback )
|
|
6535
|
+
{
|
|
6536
|
+
trigger.click();
|
|
6537
|
+
}
|
|
6538
|
+
};
|
|
6539
|
+
}
|
|
6540
|
+
|
|
6541
|
+
trigger.addEventListener( "click", e => {
|
|
5883
6542
|
if( options.selectable )
|
|
5884
6543
|
{
|
|
5885
6544
|
if( options.parent )
|
|
5886
6545
|
{
|
|
5887
|
-
options.parent.querySelectorAll(".lexbutton.selected").forEach(
|
|
6546
|
+
options.parent.querySelectorAll(".lexbutton.selected").forEach( b => { if( b == wValue ) return; b.classList.remove( "selected" ) } );
|
|
5888
6547
|
}
|
|
5889
6548
|
|
|
5890
6549
|
wValue.classList.toggle('selected');
|
|
5891
6550
|
}
|
|
5892
6551
|
|
|
5893
|
-
|
|
6552
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6553
|
+
this._trigger( new IEvent( name, swapInput?.checked ?? value, e ), callback );
|
|
5894
6554
|
});
|
|
5895
6555
|
|
|
5896
6556
|
if( options.tooltip )
|
|
@@ -6285,7 +6945,7 @@ class Select extends Widget {
|
|
|
6285
6945
|
|
|
6286
6946
|
const selectRoot = selectedOption.root;
|
|
6287
6947
|
const rect = selectRoot.getBoundingClientRect();
|
|
6288
|
-
const nestedDialog = parent.parentElement.closest( "dialog" );
|
|
6948
|
+
const nestedDialog = parent.parentElement.closest( "dialog" ) ?? parent.parentElement.closest( ".lexcolorpicker" );
|
|
6289
6949
|
|
|
6290
6950
|
// Manage vertical aspect
|
|
6291
6951
|
{
|
|
@@ -7335,31 +7995,52 @@ class ColorInput extends Widget {
|
|
|
7335
7995
|
|
|
7336
7996
|
constructor( name, value, callback, options = {} ) {
|
|
7337
7997
|
|
|
7338
|
-
|
|
7998
|
+
const useAlpha = options.useAlpha ??
|
|
7999
|
+
( ( value.constructor === Object && 'a' in value ) || ( value.constructor === String && [ 5, 9 ].includes( value.length ) ) );
|
|
8000
|
+
|
|
8001
|
+
const widgetColor = new Color( value );
|
|
8002
|
+
|
|
8003
|
+
// Force always hex internally
|
|
8004
|
+
value = useAlpha ? widgetColor.hex : widgetColor.hex.substr( 0, 7 );
|
|
7339
8005
|
|
|
7340
8006
|
super( Widget.COLOR, name, value, options );
|
|
7341
8007
|
|
|
7342
8008
|
this.onGetValue = () => {
|
|
7343
|
-
|
|
8009
|
+
const currentColor = new Color( value );
|
|
8010
|
+
return options.useRGB ? currentColor.rgb : value;
|
|
7344
8011
|
};
|
|
7345
8012
|
|
|
7346
8013
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
7347
8014
|
|
|
7348
|
-
|
|
8015
|
+
const newColor = new Color( newValue );
|
|
8016
|
+
|
|
8017
|
+
colorSampleRGB.style.color = value = newColor.hex.substr( 0, 7 );
|
|
8018
|
+
|
|
8019
|
+
if( useAlpha )
|
|
7349
8020
|
{
|
|
7350
|
-
|
|
8021
|
+
colorSampleAlpha.style.color = value = newColor.hex;
|
|
7351
8022
|
}
|
|
7352
8023
|
|
|
7353
8024
|
if( !this._skipTextUpdate )
|
|
7354
8025
|
{
|
|
7355
|
-
textWidget.set(
|
|
8026
|
+
textWidget.set( value, true, event );
|
|
7356
8027
|
}
|
|
7357
8028
|
|
|
7358
|
-
color.value = value = newValue;
|
|
7359
|
-
|
|
7360
8029
|
if( !skipCallback )
|
|
7361
8030
|
{
|
|
7362
|
-
|
|
8031
|
+
let retValue = value;
|
|
8032
|
+
|
|
8033
|
+
if( options.useRGB )
|
|
8034
|
+
{
|
|
8035
|
+
retValue = newColor.rgb;
|
|
8036
|
+
|
|
8037
|
+
if( !useAlpha )
|
|
8038
|
+
{
|
|
8039
|
+
delete retValue.a;
|
|
8040
|
+
}
|
|
8041
|
+
}
|
|
8042
|
+
|
|
8043
|
+
this._trigger( new IEvent( name, retValue, event ), callback );
|
|
7363
8044
|
}
|
|
7364
8045
|
};
|
|
7365
8046
|
|
|
@@ -7372,30 +8053,50 @@ class ColorInput extends Widget {
|
|
|
7372
8053
|
container.className = "lexcolor";
|
|
7373
8054
|
this.root.appendChild( container );
|
|
7374
8055
|
|
|
7375
|
-
let
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
8056
|
+
let sampleContainer = LX.makeContainer( ["18px", "18px"], "flex flex-row bg-contrast rounded overflow-hidden", "", container );
|
|
8057
|
+
sampleContainer.tabIndex = "1";
|
|
8058
|
+
sampleContainer.addEventListener( "click", e => {
|
|
8059
|
+
if( ( options.disabled ?? false ) )
|
|
8060
|
+
{
|
|
8061
|
+
return;
|
|
8062
|
+
}
|
|
8063
|
+
new ColorPicker( value, sampleContainer, {
|
|
8064
|
+
colorModel: options.useRGB ? "RGB" : "Hex",
|
|
8065
|
+
useAlpha,
|
|
8066
|
+
onChange: ( color ) => {
|
|
8067
|
+
this._fromColorPicker = true;
|
|
8068
|
+
this.set( color.hex );
|
|
8069
|
+
delete this._fromColorPicker;
|
|
8070
|
+
}
|
|
8071
|
+
} );
|
|
8072
|
+
} );
|
|
8073
|
+
|
|
8074
|
+
let colorSampleRGB = document.createElement( 'div' );
|
|
8075
|
+
colorSampleRGB.className = "lexcolorsample";
|
|
8076
|
+
colorSampleRGB.style.color = value;
|
|
8077
|
+
sampleContainer.appendChild( colorSampleRGB );
|
|
7382
8078
|
|
|
7383
|
-
|
|
8079
|
+
let colorSampleAlpha = null;
|
|
8080
|
+
|
|
8081
|
+
if( useAlpha )
|
|
7384
8082
|
{
|
|
7385
|
-
|
|
8083
|
+
colorSampleAlpha = document.createElement( 'div' );
|
|
8084
|
+
colorSampleAlpha.className = "lexcolorsample";
|
|
8085
|
+
colorSampleAlpha.style.color = value;
|
|
8086
|
+
sampleContainer.appendChild( colorSampleAlpha );
|
|
8087
|
+
}
|
|
8088
|
+
else
|
|
8089
|
+
{
|
|
8090
|
+
colorSampleRGB.style.width = "18px";
|
|
7386
8091
|
}
|
|
7387
8092
|
|
|
7388
|
-
|
|
7389
|
-
this.set( e.target.value, false, e );
|
|
7390
|
-
}, false );
|
|
7391
|
-
|
|
7392
|
-
const textWidget = new TextInput( null, color.value, v => {
|
|
8093
|
+
const textWidget = new TextInput( null, value, v => {
|
|
7393
8094
|
this._skipTextUpdate = true;
|
|
7394
8095
|
this.set( v );
|
|
7395
8096
|
delete this._skipTextUpdate;
|
|
7396
|
-
}, { width: "calc( 100% -
|
|
8097
|
+
}, { width: "calc( 100% - 24px )", disabled: options.disabled });
|
|
7397
8098
|
|
|
7398
|
-
textWidget.root.style.marginLeft = "
|
|
8099
|
+
textWidget.root.style.marginLeft = "6px";
|
|
7399
8100
|
container.appendChild( textWidget.root );
|
|
7400
8101
|
|
|
7401
8102
|
doAsync( this.onResize.bind( this ) );
|
|
@@ -8103,6 +8804,164 @@ class SizeInput extends Widget {
|
|
|
8103
8804
|
|
|
8104
8805
|
LX.SizeInput = SizeInput;
|
|
8105
8806
|
|
|
8807
|
+
/**
|
|
8808
|
+
* @class OTPInput
|
|
8809
|
+
* @description OTPInput Widget
|
|
8810
|
+
*/
|
|
8811
|
+
|
|
8812
|
+
class OTPInput extends Widget {
|
|
8813
|
+
|
|
8814
|
+
constructor( name, value, callback, options = {} ) {
|
|
8815
|
+
|
|
8816
|
+
const pattern = options.pattern ?? "xxx-xxx";
|
|
8817
|
+
const patternSize = ( pattern.match(/x/g) || [] ).length;
|
|
8818
|
+
|
|
8819
|
+
value = String( value );
|
|
8820
|
+
if( !value.length )
|
|
8821
|
+
{
|
|
8822
|
+
value = "x".repeat( patternSize );
|
|
8823
|
+
}
|
|
8824
|
+
|
|
8825
|
+
super( Widget.OTP, name, value, options );
|
|
8826
|
+
|
|
8827
|
+
this.onGetValue = () => {
|
|
8828
|
+
return +value;
|
|
8829
|
+
};
|
|
8830
|
+
|
|
8831
|
+
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
8832
|
+
|
|
8833
|
+
value = newValue;
|
|
8834
|
+
|
|
8835
|
+
_refreshInput( value );
|
|
8836
|
+
|
|
8837
|
+
if( !skipCallback )
|
|
8838
|
+
{
|
|
8839
|
+
this._trigger( new IEvent( name, +newValue, event ), callback );
|
|
8840
|
+
}
|
|
8841
|
+
};
|
|
8842
|
+
|
|
8843
|
+
this.onResize = ( rect ) => {
|
|
8844
|
+
const realNameWidth = ( this.root.domName?.offsetWidth ?? 0 );
|
|
8845
|
+
container.style.width = `calc( 100% - ${ realNameWidth }px)`;
|
|
8846
|
+
};
|
|
8847
|
+
|
|
8848
|
+
this.disabled = options.disabled ?? false;
|
|
8849
|
+
|
|
8850
|
+
const container = document.createElement( 'div' );
|
|
8851
|
+
container.className = "lexotp flex flex-row items-center";
|
|
8852
|
+
this.root.appendChild( container );
|
|
8853
|
+
|
|
8854
|
+
const groups = pattern.split( '-' );
|
|
8855
|
+
|
|
8856
|
+
const _refreshInput = ( valueString ) => {
|
|
8857
|
+
|
|
8858
|
+
container.innerHTML = "";
|
|
8859
|
+
|
|
8860
|
+
let itemsCount = 0;
|
|
8861
|
+
let activeSlot = 0;
|
|
8862
|
+
|
|
8863
|
+
for( let i = 0; i < groups.length; ++i )
|
|
8864
|
+
{
|
|
8865
|
+
const g = groups[ i ];
|
|
8866
|
+
|
|
8867
|
+
for( let j = 0; j < g.length; ++j )
|
|
8868
|
+
{
|
|
8869
|
+
let number = valueString[ itemsCount++ ];
|
|
8870
|
+
number = ( number == 'x' ? '' : number );
|
|
8871
|
+
|
|
8872
|
+
const slotDom = LX.makeContainer( ["36px", "30px"],
|
|
8873
|
+
"lexotpslot border-top border-bottom border-left px-3 cursor-text select-none font-medium outline-none", number, container );
|
|
8874
|
+
slotDom.tabIndex = "1";
|
|
8875
|
+
|
|
8876
|
+
if( this.disabled )
|
|
8877
|
+
{
|
|
8878
|
+
slotDom.classList.add( "disabled" );
|
|
8879
|
+
}
|
|
8880
|
+
|
|
8881
|
+
const otpIndex = itemsCount;
|
|
8882
|
+
|
|
8883
|
+
if( j == 0 )
|
|
8884
|
+
{
|
|
8885
|
+
slotDom.className += " rounded-l";
|
|
8886
|
+
}
|
|
8887
|
+
else if( j == ( g.length - 1 ) )
|
|
8888
|
+
{
|
|
8889
|
+
slotDom.className += " rounded-r border-right";
|
|
8890
|
+
}
|
|
8891
|
+
|
|
8892
|
+
slotDom.addEventListener( "click", () => {
|
|
8893
|
+
if( this.disabled ) { return; }
|
|
8894
|
+
container.querySelectorAll( ".lexotpslot" ).forEach( s => s.classList.remove( "active" ) );
|
|
8895
|
+
const activeDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot ];
|
|
8896
|
+
activeDom.classList.add( "active" );
|
|
8897
|
+
activeDom.focus();
|
|
8898
|
+
} );
|
|
8899
|
+
|
|
8900
|
+
slotDom.addEventListener( "blur", () => {
|
|
8901
|
+
if( this.disabled ) { return; }
|
|
8902
|
+
doAsync( () => {
|
|
8903
|
+
if( container.contains( document.activeElement ) ) { return; }
|
|
8904
|
+
container.querySelectorAll( ".lexotpslot" ).forEach( s => s.classList.remove( "active" ) );
|
|
8905
|
+
}, 10 );
|
|
8906
|
+
} );
|
|
8907
|
+
|
|
8908
|
+
slotDom.addEventListener( "keyup", e => {
|
|
8909
|
+
if( this.disabled ) { return; }
|
|
8910
|
+
if( !/[^0-9]+/g.test( e.key ) )
|
|
8911
|
+
{
|
|
8912
|
+
const number = e.key;
|
|
8913
|
+
console.assert( parseInt( number ) != NaN );
|
|
8914
|
+
|
|
8915
|
+
slotDom.innerHTML = number;
|
|
8916
|
+
valueString = valueString.substring( 0, otpIndex - 1 ) + number + valueString.substring( otpIndex );
|
|
8917
|
+
|
|
8918
|
+
const nexActiveDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot + 1 ];
|
|
8919
|
+
if( nexActiveDom )
|
|
8920
|
+
{
|
|
8921
|
+
container.querySelectorAll( ".lexotpslot" )[ activeSlot ].classList.remove( "active" );
|
|
8922
|
+
nexActiveDom.classList.add( "active" );
|
|
8923
|
+
nexActiveDom.focus();
|
|
8924
|
+
activeSlot++;
|
|
8925
|
+
}
|
|
8926
|
+
else
|
|
8927
|
+
{
|
|
8928
|
+
this.set( valueString );
|
|
8929
|
+
}
|
|
8930
|
+
}
|
|
8931
|
+
else if( e.key == "ArrowLeft" || e.key == "ArrowRight" )
|
|
8932
|
+
{
|
|
8933
|
+
const dt = ( e.key == "ArrowLeft" ) ? -1 : 1;
|
|
8934
|
+
const newActiveDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot + dt ];
|
|
8935
|
+
if( newActiveDom )
|
|
8936
|
+
{
|
|
8937
|
+
container.querySelectorAll( ".lexotpslot" )[ activeSlot ].classList.remove( "active" );
|
|
8938
|
+
newActiveDom.classList.add( "active" );
|
|
8939
|
+
newActiveDom.focus();
|
|
8940
|
+
activeSlot += dt;
|
|
8941
|
+
}
|
|
8942
|
+
}
|
|
8943
|
+
else if( e.key == "Enter" && !valueString.includes( 'x' ) )
|
|
8944
|
+
{
|
|
8945
|
+
this.set( valueString );
|
|
8946
|
+
}
|
|
8947
|
+
} );
|
|
8948
|
+
}
|
|
8949
|
+
|
|
8950
|
+
if( i < ( groups.length - 1 ) )
|
|
8951
|
+
{
|
|
8952
|
+
LX.makeContainer( ["auto", "auto"], "mx-2", `-`, container );
|
|
8953
|
+
}
|
|
8954
|
+
}
|
|
8955
|
+
|
|
8956
|
+
console.assert( itemsCount == valueString.length, "OTP Value/Pattern Mismatch!" )
|
|
8957
|
+
}
|
|
8958
|
+
|
|
8959
|
+
_refreshInput( value );
|
|
8960
|
+
}
|
|
8961
|
+
}
|
|
8962
|
+
|
|
8963
|
+
LX.OTPInput = OTPInput;
|
|
8964
|
+
|
|
8106
8965
|
/**
|
|
8107
8966
|
* @class Pad
|
|
8108
8967
|
* @description Pad Widget
|
|
@@ -8870,7 +9729,7 @@ class Table extends Widget {
|
|
|
8870
9729
|
for( const el of body.childNodes )
|
|
8871
9730
|
{
|
|
8872
9731
|
data.checkMap[ el.getAttribute( "rowId" ) ] = this.checked;
|
|
8873
|
-
el.querySelector( "input" ).checked = this.checked;
|
|
9732
|
+
el.querySelector( "input[type='checkbox']" ).checked = this.checked;
|
|
8874
9733
|
}
|
|
8875
9734
|
});
|
|
8876
9735
|
|
|
@@ -9084,10 +9943,20 @@ class Table extends Widget {
|
|
|
9084
9943
|
input.addEventListener( 'change', function() {
|
|
9085
9944
|
data.checkMap[ rowId ] = this.checked;
|
|
9086
9945
|
|
|
9946
|
+
const headInput = table.querySelector( "thead input[type='checkbox']" );
|
|
9947
|
+
|
|
9087
9948
|
if( !this.checked )
|
|
9088
9949
|
{
|
|
9089
|
-
|
|
9090
|
-
|
|
9950
|
+
headInput.checked = data.checkMap[ ":root" ] = false;
|
|
9951
|
+
}
|
|
9952
|
+
else
|
|
9953
|
+
{
|
|
9954
|
+
const rowInputs = Array.from( table.querySelectorAll( "tbody input[type='checkbox']" ) );
|
|
9955
|
+
const uncheckedRowInputs = rowInputs.filter( i => { return !i.checked; } );
|
|
9956
|
+
if( !uncheckedRowInputs.length )
|
|
9957
|
+
{
|
|
9958
|
+
headInput.checked = data.checkMap[ ":root" ] = true;
|
|
9959
|
+
}
|
|
9091
9960
|
}
|
|
9092
9961
|
});
|
|
9093
9962
|
|
|
@@ -10198,6 +11067,22 @@ class Panel {
|
|
|
10198
11067
|
return this._attachWidget( widget );
|
|
10199
11068
|
}
|
|
10200
11069
|
|
|
11070
|
+
/**
|
|
11071
|
+
* @method addOTP
|
|
11072
|
+
* @param {String} name Widget name
|
|
11073
|
+
* @param {String} value Default numeric value in string format
|
|
11074
|
+
* @param {Function} callback Callback function on change
|
|
11075
|
+
* @param {Object} options:
|
|
11076
|
+
* hideName: Don't use name as label [false]
|
|
11077
|
+
* disabled: Make the widget disabled [false]
|
|
11078
|
+
* pattern: OTP numeric pattern
|
|
11079
|
+
*/
|
|
11080
|
+
|
|
11081
|
+
addOTP( name, value, callback, options = {} ) {
|
|
11082
|
+
const widget = new OTPInput( name, value, callback, options );
|
|
11083
|
+
return this._attachWidget( widget );
|
|
11084
|
+
}
|
|
11085
|
+
|
|
10201
11086
|
/**
|
|
10202
11087
|
* @method addPad
|
|
10203
11088
|
* @param {String} name Widget name
|
|
@@ -10430,7 +11315,7 @@ class Branch {
|
|
|
10430
11315
|
// add widgets
|
|
10431
11316
|
for( let w of this.widgets )
|
|
10432
11317
|
{
|
|
10433
|
-
p.root.appendChild( w.
|
|
11318
|
+
p.root.appendChild( w.root );
|
|
10434
11319
|
}
|
|
10435
11320
|
});
|
|
10436
11321
|
dialog.widgets = this.widgets;
|
|
@@ -10734,7 +11619,7 @@ class Dialog {
|
|
|
10734
11619
|
|
|
10735
11620
|
for( let w of that.widgets )
|
|
10736
11621
|
{
|
|
10737
|
-
branch.content.appendChild( w.
|
|
11622
|
+
branch.content.appendChild( w.root );
|
|
10738
11623
|
}
|
|
10739
11624
|
|
|
10740
11625
|
branch.widgets = that.widgets;
|
|
@@ -12375,7 +13260,7 @@ class AssetView {
|
|
|
12375
13260
|
|
|
12376
13261
|
this.rightPanel.addText(null, this.path.join('/'), null, {
|
|
12377
13262
|
inputClass: "nobg", disabled: true, signal: "@on_folder_change",
|
|
12378
|
-
style: { fontWeight: "600", fontSize: "15px" }
|
|
13263
|
+
style: { fontWeight: "600", fontSize: "15px" }
|
|
12379
13264
|
});
|
|
12380
13265
|
|
|
12381
13266
|
this.rightPanel.endLine();
|
|
@@ -13112,7 +13997,7 @@ Element.prototype.addClass = function( className ) {
|
|
|
13112
13997
|
}
|
|
13113
13998
|
|
|
13114
13999
|
Element.prototype.getComputedSize = function() {
|
|
13115
|
-
// Since we use "box-sizing: border-box" now,
|
|
14000
|
+
// Since we use "box-sizing: border-box" now,
|
|
13116
14001
|
// it's all included in offsetWidth/offsetHeight
|
|
13117
14002
|
return {
|
|
13118
14003
|
width: this.offsetWidth,
|
|
@@ -13254,6 +14139,7 @@ LX.ICONS = {
|
|
|
13254
14139
|
"copy": [448, 512, [], "regular", "M384 336l-192 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l140.1 0L400 115.9 400 320c0 8.8-7.2 16-16 16zM192 384l192 0c35.3 0 64-28.7 64-64l0-204.1c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1L192 0c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l192 0c35.3 0 64-28.7 64-64l0-32-48 0 0 32c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l32 0 0-48-32 0z"],
|
|
13255
14140
|
"paste": [512, 512, [], "regular", "M104.6 48L64 48C28.7 48 0 76.7 0 112L0 384c0 35.3 28.7 64 64 64l96 0 0-48-96 0c-8.8 0-16-7.2-16-16l0-272c0-8.8 7.2-16 16-16l16 0c0 17.7 14.3 32 32 32l72.4 0C202 108.4 227.6 96 256 96l62 0c-7.1-27.6-32.2-48-62-48l-40.6 0C211.6 20.9 188.2 0 160 0s-51.6 20.9-55.4 48zM144 56a16 16 0 1 1 32 0 16 16 0 1 1 -32 0zM448 464l-192 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l140.1 0L464 243.9 464 448c0 8.8-7.2 16-16 16zM256 512l192 0c35.3 0 64-28.7 64-64l0-204.1c0-12.7-5.1-24.9-14.1-33.9l-67.9-67.9c-9-9-21.2-14.1-33.9-14.1L256 128c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64z"],
|
|
13256
14141
|
"clipboard": [384, 512, [], "regular", "M280 64l40 0c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 128C0 92.7 28.7 64 64 64l40 0 9.6 0C121 27.5 153.3 0 192 0s71 27.5 78.4 64l9.6 0zM64 112c-8.8 0-16 7.2-16 16l0 320c0 8.8 7.2 16 16 16l256 0c8.8 0 16-7.2 16-16l0-320c0-8.8-7.2-16-16-16l-16 0 0 24c0 13.3-10.7 24-24 24l-88 0-88 0c-13.3 0-24-10.7-24-24l0-24-16 0zm128-8a24 24 0 1 0 0-48 24 24 0 1 0 0 48z"],
|
|
14142
|
+
"eye-dropper": [512, 512, [], "solid", "M341.6 29.2L240.1 130.8l-9.4-9.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-9.4-9.4L482.8 170.4c39-39 39-102.2 0-141.1s-102.2-39-141.1 0zM55.4 323.3c-15 15-23.4 35.4-23.4 56.6l0 42.4L5.4 462.2c-8.5 12.7-6.8 29.6 4 40.4s27.7 12.5 40.4 4L89.7 480l42.4 0c21.2 0 41.6-8.4 56.6-23.4L309.4 335.9l-45.3-45.3L143.4 411.3c-3 3-7.1 4.7-11.3 4.7L96 416l0-36.1c0-4.2 1.7-8.3 4.7-11.3L221.4 247.9l-45.3-45.3L55.4 323.3z"],
|
|
13257
14143
|
"edit": [512, 512, [], "regular", "M441 58.9L453.1 71c9.4 9.4 9.4 24.6 0 33.9L424 134.1 377.9 88 407 58.9c9.4-9.4 24.6-9.4 33.9 0zM209.8 256.2L344 121.9 390.1 168 255.8 302.2c-2.9 2.9-6.5 5-10.4 6.1l-58.5 16.7 16.7-58.5c1.1-3.9 3.2-7.5 6.1-10.4zM373.1 25L175.8 222.2c-8.7 8.7-15 19.4-18.3 31.1l-28.6 100c-2.4 8.4-.1 17.4 6.1 23.6s15.2 8.5 23.6 6.1l100-28.6c11.8-3.4 22.5-9.7 31.1-18.3L487 138.9c28.1-28.1 28.1-73.7 0-101.8L474.9 25C446.8-3.1 401.2-3.1 373.1 25zM88 64C39.4 64 0 103.4 0 152L0 424c0 48.6 39.4 88 88 88l272 0c48.6 0 88-39.4 88-88l0-112c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 112c0 22.1-17.9 40-40 40L88 464c-22.1 0-40-17.9-40-40l0-272c0-22.1 17.9-40 40-40l112 0c13.3 0 24-10.7 24-24s-10.7-24-24-24L88 64z"],
|
|
13258
14144
|
"envelope": [512, 512, [], "regular", "M64 112c-8.8 0-16 7.2-16 16l0 22.1L220.5 291.7c20.7 17 50.4 17 71.1 0L464 150.1l0-22.1c0-8.8-7.2-16-16-16L64 112zM48 212.2L48 384c0 8.8 7.2 16 16 16l384 0c8.8 0 16-7.2 16-16l0-171.8L322 328.8c-38.4 31.5-93.7 31.5-132 0L48 212.2zM0 128C0 92.7 28.7 64 64 64l384 0c35.3 0 64 28.7 64 64l0 256c0 35.3-28.7 64-64 64L64 448c-35.3 0-64-28.7-64-64L0 128z"],
|
|
13259
14145
|
"envelope-open": [512, 512, [], "regular", "M255.4 48.2c.2-.1 .4-.2 .6-.2s.4 .1 .6 .2L460.6 194c2.1 1.5 3.4 3.9 3.4 6.5l0 13.6L291.5 355.7c-20.7 17-50.4 17-71.1 0L48 214.1l0-13.6c0-2.6 1.2-5 3.4-6.5L255.4 48.2zM48 276.2L190 392.8c38.4 31.5 93.7 31.5 132 0L464 276.2 464 456c0 4.4-3.6 8-8 8L56 464c-4.4 0-8-3.6-8-8l0-179.8zM256 0c-10.2 0-20.2 3.2-28.5 9.1L23.5 154.9C8.7 165.4 0 182.4 0 200.5L0 456c0 30.9 25.1 56 56 56l400 0c30.9 0 56-25.1 56-56l0-255.5c0-18.1-8.7-35.1-23.4-45.6L284.5 9.1C276.2 3.2 266.2 0 256 0z"],
|