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.module.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
var LX = {
|
|
9
|
-
version: "0.5.
|
|
9
|
+
version: "0.5.6",
|
|
10
10
|
ready: false,
|
|
11
11
|
components: [], // Specific pre-build components
|
|
12
12
|
signals: {}, // Events and triggers
|
|
@@ -216,37 +216,141 @@ LX.getBase64Image = getBase64Image;
|
|
|
216
216
|
|
|
217
217
|
/**
|
|
218
218
|
* @method hexToRgb
|
|
219
|
-
* @description Convert a hexadecimal string to a valid RGB color
|
|
220
|
-
* @param {String}
|
|
219
|
+
* @description Convert a hexadecimal string to a valid RGB color
|
|
220
|
+
* @param {String} hex Hexadecimal color
|
|
221
221
|
*/
|
|
222
|
-
function hexToRgb(
|
|
222
|
+
function hexToRgb( hex )
|
|
223
223
|
{
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
224
|
+
const hexPattern = /^#(?:[A-Fa-f0-9]{3,4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/;
|
|
225
|
+
if( !hexPattern.test( hex ) )
|
|
226
|
+
{
|
|
227
|
+
throw( `Invalid Hex Color: ${ hex }` );
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
hex = hex.replace( /^#/, '' );
|
|
231
|
+
|
|
232
|
+
// Expand shorthand form (#RGB or #RGBA)
|
|
233
|
+
if( hex.length === 3 || hex.length === 4 )
|
|
234
|
+
{
|
|
235
|
+
hex = hex.split( '' ).map( c => c + c ).join( '' );
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const bigint = parseInt( hex, 16 );
|
|
239
|
+
|
|
240
|
+
const r = ( ( bigint >> ( hex.length === 8 ? 24 : 16 ) ) & 255 ) / 255;
|
|
241
|
+
const g = ( ( bigint >> ( hex.length === 8 ? 16 : 8 ) ) & 255 ) / 255;
|
|
242
|
+
const b = ( ( bigint >> ( hex.length === 8 ? 8 : 0 ) ) & 255 ) / 255;
|
|
243
|
+
const a = ( hex.length === 8 ? ( bigint & 255 ) : ( hex.length === 4 ? parseInt( hex.slice( -2 ), 16 ) : 255 ) ) / 255;
|
|
244
|
+
|
|
245
|
+
return { r, g, b, a };
|
|
228
246
|
}
|
|
229
247
|
|
|
230
248
|
LX.hexToRgb = hexToRgb;
|
|
231
249
|
|
|
250
|
+
/**
|
|
251
|
+
* @method hexToHsv
|
|
252
|
+
* @description Convert a hexadecimal string to HSV (0..360|0..1|0..1)
|
|
253
|
+
* @param {String} hexStr Hexadecimal color
|
|
254
|
+
*/
|
|
255
|
+
function hexToHsv( hexStr )
|
|
256
|
+
{
|
|
257
|
+
const rgb = hexToRgb( hexStr );
|
|
258
|
+
return rgbToHsv( rgb );
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
LX.hexToHsv = hexToHsv;
|
|
262
|
+
|
|
232
263
|
/**
|
|
233
264
|
* @method rgbToHex
|
|
234
|
-
* @description Convert a RGB color
|
|
235
|
-
* @param {
|
|
265
|
+
* @description Convert a RGB color to a hexadecimal string
|
|
266
|
+
* @param {Object} rgb Object containing RGB color
|
|
267
|
+
* @param {Number} scale Use 255 for 0..255 range or 1 for 0..1 range
|
|
236
268
|
*/
|
|
237
|
-
function rgbToHex( rgb )
|
|
269
|
+
function rgbToHex( rgb, scale = 255 )
|
|
238
270
|
{
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
271
|
+
const rgbArray = [ rgb.r, rgb.g, rgb.b ];
|
|
272
|
+
if( rgb.a != undefined ) rgbArray.push( rgb.a );
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
"#" +
|
|
276
|
+
rgbArray.map( c => {
|
|
277
|
+
c = Math.floor( c * scale );
|
|
278
|
+
const hex = c.toString(16);
|
|
279
|
+
return hex.length === 1 ? ( '0' + hex ) : hex;
|
|
280
|
+
}).join("")
|
|
281
|
+
);
|
|
246
282
|
}
|
|
247
283
|
|
|
248
284
|
LX.rgbToHex = rgbToHex;
|
|
249
285
|
|
|
286
|
+
/**
|
|
287
|
+
* @method rgbToCss
|
|
288
|
+
* @description Convert a RGB color (0..1) to a CSS color format
|
|
289
|
+
* @param {Object} rgb Object containing RGB color
|
|
290
|
+
*/
|
|
291
|
+
function rgbToCss( rgb )
|
|
292
|
+
{
|
|
293
|
+
return { r: Math.floor( rgb.r * 255 ), g: Math.floor( rgb.g * 255 ), b: Math.floor( rgb.b * 255 ), a: rgb.a };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
LX.rgbToCss = rgbToCss;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* @method rgbToHsv
|
|
300
|
+
* @description Convert a RGB color (0..1) array to HSV (0..360|0..1|0..1)
|
|
301
|
+
* @param {Object} rgb Array containing R, G, B
|
|
302
|
+
*/
|
|
303
|
+
function rgbToHsv( rgb )
|
|
304
|
+
{
|
|
305
|
+
let { r, g, b, a } = rgb;
|
|
306
|
+
a = a ?? 1;
|
|
307
|
+
|
|
308
|
+
const max = Math.max(r, g, b);
|
|
309
|
+
const min = Math.min(r, g, b);
|
|
310
|
+
const d = max - min;
|
|
311
|
+
let h = 0;
|
|
312
|
+
|
|
313
|
+
if (d !== 0) {
|
|
314
|
+
if (max === r) { h = ((g - b) / d) % 6 }
|
|
315
|
+
else if (max === g) { h = (b - r) / d + 2 }
|
|
316
|
+
else { h = (r - g) / d + 4 }
|
|
317
|
+
h *= 60
|
|
318
|
+
if (h < 0) { h += 360 }
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const s = max === 0 ? 0 : (d / max);
|
|
322
|
+
const v = max;
|
|
323
|
+
|
|
324
|
+
return { h, s, v, a };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
LX.rgbToHsv = rgbToHsv;
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @method hsvToRgb
|
|
331
|
+
* @description Convert an HSV color (0..360|0..1|0..1) array to RGB (0..1|0..255)
|
|
332
|
+
* @param {Array} hsv Array containing H, S, V
|
|
333
|
+
*/
|
|
334
|
+
function hsvToRgb( hsv )
|
|
335
|
+
{
|
|
336
|
+
const { h, s, v, a } = hsv;
|
|
337
|
+
const c = v * s;
|
|
338
|
+
const x = c * (1 - Math.abs( ( (h / 60) % 2 ) - 1) )
|
|
339
|
+
const m = v - c;
|
|
340
|
+
let r = 0, g = 0, b = 0;
|
|
341
|
+
|
|
342
|
+
if( h < 60 ) { r = c; g = x; b = 0; }
|
|
343
|
+
else if ( h < 120 ) { r = x; g = c; b = 0; }
|
|
344
|
+
else if ( h < 180 ) { r = 0; g = c; b = x; }
|
|
345
|
+
else if ( h < 240 ) { r = 0; g = x; b = c; }
|
|
346
|
+
else if ( h < 300 ) { r = x; g = 0; b = c; }
|
|
347
|
+
else { r = c; g = 0; b = x; }
|
|
348
|
+
|
|
349
|
+
return { r: ( r + m ), g: ( g + m ), b: ( b + m ), a };
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
LX.hsvToRgb = hsvToRgb;
|
|
353
|
+
|
|
250
354
|
/**
|
|
251
355
|
* @method measureRealWidth
|
|
252
356
|
* @description Measure the pixel width of a text
|
|
@@ -578,6 +682,42 @@ function makeCodeSnippet( code, size, options = { } )
|
|
|
578
682
|
|
|
579
683
|
LX.makeCodeSnippet = makeCodeSnippet;
|
|
580
684
|
|
|
685
|
+
/**
|
|
686
|
+
* @method makeKbd
|
|
687
|
+
* @description Kbd element to display a keyboard key.
|
|
688
|
+
* @param {Array} keys
|
|
689
|
+
* @param {String} extraClass
|
|
690
|
+
*/
|
|
691
|
+
function makeKbd( keys, extraClass = "" )
|
|
692
|
+
{
|
|
693
|
+
const specialKeys = {
|
|
694
|
+
"Ctrl": '⌃',
|
|
695
|
+
"Enter": '↩',
|
|
696
|
+
"Shift": '⇧',
|
|
697
|
+
"CapsLock": '⇪',
|
|
698
|
+
"Meta": '⌘',
|
|
699
|
+
"Option": '⌥',
|
|
700
|
+
"Alt": '⌥',
|
|
701
|
+
"Tab": '⇥',
|
|
702
|
+
"ArrowUp": '↑',
|
|
703
|
+
"ArrowDown": '↓',
|
|
704
|
+
"ArrowLeft": '←',
|
|
705
|
+
"ArrowRight": '→',
|
|
706
|
+
"Space": '␣'
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
const kbd = LX.makeContainer( ["auto", "auto"], "flex flex-row ml-auto" );
|
|
710
|
+
|
|
711
|
+
for( const k of keys )
|
|
712
|
+
{
|
|
713
|
+
LX.makeContainer( ["auto", "auto"], "self-center text-xs fg-secondary select-none", specialKeys[ k ] ?? k, kbd );
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
return kbd;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
LX.makeKbd = makeKbd;
|
|
720
|
+
|
|
581
721
|
/**
|
|
582
722
|
* @method makeIcon
|
|
583
723
|
* @description Gets an SVG element using one of LX.ICONS
|
|
@@ -716,7 +856,7 @@ function registerCommandbarEntry( name, callback )
|
|
|
716
856
|
|
|
717
857
|
LX.registerCommandbarEntry = registerCommandbarEntry;
|
|
718
858
|
|
|
719
|
-
//
|
|
859
|
+
// Utils classes
|
|
720
860
|
|
|
721
861
|
class vec2 {
|
|
722
862
|
|
|
@@ -744,6 +884,77 @@ class vec2 {
|
|
|
744
884
|
|
|
745
885
|
LX.vec2 = vec2;
|
|
746
886
|
|
|
887
|
+
class Color {
|
|
888
|
+
|
|
889
|
+
constructor( value ) {
|
|
890
|
+
|
|
891
|
+
Object.defineProperty( Color.prototype, "rgb", {
|
|
892
|
+
get: function() { return this._rgb; },
|
|
893
|
+
set: function( v ) { this._fromRGB( v ) }, enumerable: true, configurable: true
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
Object.defineProperty( Color.prototype, "hex", {
|
|
897
|
+
get: function() { return this._hex; },
|
|
898
|
+
set: function( v ) { this._fromHex( v ) }, enumerable: true, configurable: true
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
Object.defineProperty( Color.prototype, "hsv", {
|
|
902
|
+
get: function() { return this._hsv; },
|
|
903
|
+
set: function( v ) { this._fromHSV( v ) }, enumerable: true, configurable: true
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
this.set( value );
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
set( value ) {
|
|
910
|
+
|
|
911
|
+
if ( typeof value === 'string' && value.startsWith( '#' ) )
|
|
912
|
+
{
|
|
913
|
+
this._fromHex( value );
|
|
914
|
+
}
|
|
915
|
+
else if( 'r' in value && 'g' in value && 'b' in value)
|
|
916
|
+
{
|
|
917
|
+
value.a = value.a ?? 1.0;
|
|
918
|
+
this._fromRGB( value );
|
|
919
|
+
}
|
|
920
|
+
else if( 'h' in value && 's' in value && 'v' in value )
|
|
921
|
+
{
|
|
922
|
+
value.a = value.a ?? 1.0;
|
|
923
|
+
this._fromHSV( value );
|
|
924
|
+
}
|
|
925
|
+
else
|
|
926
|
+
{
|
|
927
|
+
throw( "Bad color model!", value );
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
setHSV( hsv ) { this._fromHSV( hsv ); }
|
|
932
|
+
setRGB( rgb ) { this._fromRGB( rgb ); }
|
|
933
|
+
setHex( hex ) { this._fromHex( hex ); }
|
|
934
|
+
|
|
935
|
+
_fromHex( hex ) {
|
|
936
|
+
this._fromRGB( hexToRgb( hex ) );
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
_fromRGB( rgb ) {
|
|
940
|
+
this._rgb = rgb;
|
|
941
|
+
this._hsv = rgbToHsv( rgb );
|
|
942
|
+
this._hex = rgbToHex( rgb );
|
|
943
|
+
this.css = rgbToCss( this._rgb );
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
_fromHSV( hsv ) {
|
|
947
|
+
this._hsv = hsv;
|
|
948
|
+
this._rgb = hsvToRgb( hsv );
|
|
949
|
+
this._hex = rgbToHex( this._rgb );
|
|
950
|
+
this.css = rgbToCss( this._rgb );
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
LX.Color = Color;
|
|
955
|
+
|
|
956
|
+
// Command bar creation
|
|
957
|
+
|
|
747
958
|
function _createCommandbar( root )
|
|
748
959
|
{
|
|
749
960
|
let commandbar = document.createElement( "dialog" );
|
|
@@ -1801,6 +2012,13 @@ class DropdownMenu {
|
|
|
1801
2012
|
submenuIcon.className = "fa-solid fa-angle-right fa-xs";
|
|
1802
2013
|
menuItem.appendChild( submenuIcon );
|
|
1803
2014
|
}
|
|
2015
|
+
else if( item.kbd )
|
|
2016
|
+
{
|
|
2017
|
+
item.kbd = [].concat( item.kbd );
|
|
2018
|
+
|
|
2019
|
+
const kbd = LX.makeKbd( item.kbd );
|
|
2020
|
+
menuItem.appendChild( kbd );
|
|
2021
|
+
}
|
|
1804
2022
|
|
|
1805
2023
|
if( item.icon )
|
|
1806
2024
|
{
|
|
@@ -1820,57 +2038,508 @@ class DropdownMenu {
|
|
|
1820
2038
|
const input = checkbox.root.querySelector( "input" );
|
|
1821
2039
|
menuItem.prepend( input );
|
|
1822
2040
|
|
|
1823
|
-
menuItem.addEventListener( "click", (e) => {
|
|
1824
|
-
if( e.target.type == "checkbox" ) return;
|
|
1825
|
-
input.checked = !input.checked;
|
|
1826
|
-
checkbox.set( input.checked );
|
|
1827
|
-
} );
|
|
1828
|
-
}
|
|
1829
|
-
else
|
|
1830
|
-
{
|
|
1831
|
-
menuItem.addEventListener( "click", () => {
|
|
1832
|
-
const f = item[ 'callback' ];
|
|
1833
|
-
if( f )
|
|
1834
|
-
{
|
|
1835
|
-
f.call( this, key, menuItem );
|
|
1836
|
-
}
|
|
1837
|
-
this.destroy();
|
|
1838
|
-
} );
|
|
1839
|
-
}
|
|
2041
|
+
menuItem.addEventListener( "click", (e) => {
|
|
2042
|
+
if( e.target.type == "checkbox" ) return;
|
|
2043
|
+
input.checked = !input.checked;
|
|
2044
|
+
checkbox.set( input.checked );
|
|
2045
|
+
} );
|
|
2046
|
+
}
|
|
2047
|
+
else
|
|
2048
|
+
{
|
|
2049
|
+
menuItem.addEventListener( "click", () => {
|
|
2050
|
+
const f = item[ 'callback' ];
|
|
2051
|
+
if( f )
|
|
2052
|
+
{
|
|
2053
|
+
f.call( this, key, menuItem );
|
|
2054
|
+
}
|
|
2055
|
+
this.destroy();
|
|
2056
|
+
} );
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
menuItem.addEventListener("mouseover", e => {
|
|
2060
|
+
|
|
2061
|
+
let path = menuItem.id;
|
|
2062
|
+
let p = parentDom;
|
|
2063
|
+
|
|
2064
|
+
while( p )
|
|
2065
|
+
{
|
|
2066
|
+
path += "/" + p.id;
|
|
2067
|
+
p = p.currentParent?.parentElement;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
LX.root.querySelectorAll( ".lexdropdownmenu" ).forEach( m => {
|
|
2071
|
+
if( !path.includes( m.id ) )
|
|
2072
|
+
{
|
|
2073
|
+
m.currentParent.built = false;
|
|
2074
|
+
m.remove();
|
|
2075
|
+
}
|
|
2076
|
+
} );
|
|
2077
|
+
|
|
2078
|
+
if( item.submenu )
|
|
2079
|
+
{
|
|
2080
|
+
if( menuItem.built )
|
|
2081
|
+
{
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
menuItem.built = true;
|
|
2085
|
+
this._create( item.submenu, menuItem );
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
e.stopPropagation();
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
_adjustPosition() {
|
|
2094
|
+
|
|
2095
|
+
const position = [ 0, 0 ];
|
|
2096
|
+
|
|
2097
|
+
// Place menu using trigger position and user options
|
|
2098
|
+
{
|
|
2099
|
+
const rect = this._trigger.getBoundingClientRect();
|
|
2100
|
+
|
|
2101
|
+
let alignWidth = true;
|
|
2102
|
+
|
|
2103
|
+
switch( this.side )
|
|
2104
|
+
{
|
|
2105
|
+
case "left":
|
|
2106
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
2107
|
+
alignWidth = false;
|
|
2108
|
+
break;
|
|
2109
|
+
case "right":
|
|
2110
|
+
position[ 0 ] += ( rect.x + rect.width );
|
|
2111
|
+
alignWidth = false;
|
|
2112
|
+
break;
|
|
2113
|
+
case "top":
|
|
2114
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
2115
|
+
alignWidth = true;
|
|
2116
|
+
break;
|
|
2117
|
+
case "bottom":
|
|
2118
|
+
position[ 1 ] += ( rect.y + rect.height );
|
|
2119
|
+
alignWidth = true;
|
|
2120
|
+
break;
|
|
2121
|
+
default:
|
|
2122
|
+
break;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
switch( this.align )
|
|
2126
|
+
{
|
|
2127
|
+
case "start":
|
|
2128
|
+
if( alignWidth ) { position[ 0 ] += rect.x; }
|
|
2129
|
+
else { position[ 1 ] += rect.y; }
|
|
2130
|
+
break;
|
|
2131
|
+
case "center":
|
|
2132
|
+
if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - this.root.offsetWidth * 0.5; }
|
|
2133
|
+
else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - this.root.offsetHeight * 0.5; }
|
|
2134
|
+
break;
|
|
2135
|
+
case "end":
|
|
2136
|
+
if( alignWidth ) { position[ 0 ] += rect.x - this.root.offsetWidth + rect.width; }
|
|
2137
|
+
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
2138
|
+
break;
|
|
2139
|
+
default:
|
|
2140
|
+
break;
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
if( this.avoidCollisions )
|
|
2145
|
+
{
|
|
2146
|
+
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - this.root.offsetWidth - this._windowPadding );
|
|
2147
|
+
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - this.root.offsetHeight - this._windowPadding );
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
this.root.style.left = `${ position[ 0 ] }px`;
|
|
2151
|
+
this.root.style.top = `${ position[ 1 ] }px`;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
_addSeparator( parent ) {
|
|
2155
|
+
const separator = document.createElement('div');
|
|
2156
|
+
separator.className = "separator";
|
|
2157
|
+
parent = parent ?? this.root;
|
|
2158
|
+
parent.appendChild( separator );
|
|
2159
|
+
}
|
|
2160
|
+
};
|
|
2161
|
+
|
|
2162
|
+
LX.DropdownMenu = DropdownMenu;
|
|
2163
|
+
|
|
2164
|
+
/**
|
|
2165
|
+
* @class ColorPicker
|
|
2166
|
+
*/
|
|
2167
|
+
|
|
2168
|
+
class ColorPicker {
|
|
2169
|
+
|
|
2170
|
+
static currentPicker = false;
|
|
2171
|
+
|
|
2172
|
+
constructor( hexValue, trigger, options = {} ) {
|
|
2173
|
+
|
|
2174
|
+
console.assert( trigger, "ColorPicker needs a DOM element as trigger!" );
|
|
2175
|
+
|
|
2176
|
+
this._windowPadding = 4;
|
|
2177
|
+
this.side = options.side ?? "bottom";
|
|
2178
|
+
this.align = options.align ?? "center";
|
|
2179
|
+
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
2180
|
+
this.colorModel = options.colorModel ?? "Hex";
|
|
2181
|
+
this.useAlpha = options.useAlpha ?? false;
|
|
2182
|
+
this.callback = options.onChange;
|
|
2183
|
+
|
|
2184
|
+
if( !this.callback )
|
|
2185
|
+
{
|
|
2186
|
+
console.warn( "Define a callback in _options.onChange_ to allow getting new Color values!" );
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
if( ColorPicker.currentPicker )
|
|
2190
|
+
{
|
|
2191
|
+
ColorPicker.currentPicker.destroy();
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
this._trigger = trigger;
|
|
2196
|
+
trigger.classList.add( "triggered" );
|
|
2197
|
+
trigger.picker = this;
|
|
2198
|
+
|
|
2199
|
+
this.root = document.createElement( "div" );
|
|
2200
|
+
this.root.tabIndex = "1";
|
|
2201
|
+
this.root.className = "lexcolorpicker";
|
|
2202
|
+
this.root.dataset["side"] = this.side;
|
|
2203
|
+
LX.root.appendChild( this.root );
|
|
2204
|
+
|
|
2205
|
+
this.root.addEventListener( "keydown", (e) => {
|
|
2206
|
+
if( e.key == "Escape" )
|
|
2207
|
+
{
|
|
2208
|
+
e.preventDefault();
|
|
2209
|
+
e.stopPropagation();
|
|
2210
|
+
this.destroy();
|
|
2211
|
+
}
|
|
2212
|
+
} )
|
|
2213
|
+
|
|
2214
|
+
ColorPicker.currentPicker = this;
|
|
2215
|
+
|
|
2216
|
+
this.markerHalfSize = 8;
|
|
2217
|
+
this.markerSize = this.markerHalfSize * 2;
|
|
2218
|
+
this.currentColor = new Color( hexValue );
|
|
2219
|
+
|
|
2220
|
+
const hueColor = new Color( { h: this.currentColor.hsv.h, s: 1, v: 1 } );
|
|
2221
|
+
|
|
2222
|
+
// Intensity, Sat
|
|
2223
|
+
this.colorPickerBackground = document.createElement( 'div' );
|
|
2224
|
+
this.colorPickerBackground.className = "lexcolorpickerbg";
|
|
2225
|
+
this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2226
|
+
this.root.appendChild( this.colorPickerBackground );
|
|
2227
|
+
|
|
2228
|
+
this.intSatMarker = document.createElement( 'div' );
|
|
2229
|
+
this.intSatMarker.className = "lexcolormarker";
|
|
2230
|
+
this.intSatMarker.style.backgroundColor = this.currentColor.hex;
|
|
2231
|
+
this.colorPickerBackground.appendChild( this.intSatMarker );
|
|
2232
|
+
|
|
2233
|
+
doAsync( this._svToPosition.bind( this, this.currentColor.hsv.s, this.currentColor.hsv.v ) );
|
|
2234
|
+
|
|
2235
|
+
let innerMouseDown = e => {
|
|
2236
|
+
var doc = this.root.ownerDocument;
|
|
2237
|
+
doc.addEventListener( 'mousemove', innerMouseMove );
|
|
2238
|
+
doc.addEventListener( 'mouseup', innerMouseUp );
|
|
2239
|
+
document.body.classList.add( 'noevents' );
|
|
2240
|
+
e.stopImmediatePropagation();
|
|
2241
|
+
e.stopPropagation();
|
|
2242
|
+
|
|
2243
|
+
const currentLeft = ( e.offsetX - this.markerHalfSize );
|
|
2244
|
+
this.intSatMarker.style.left = currentLeft + "px";
|
|
2245
|
+
const currentTop = ( e.offsetY - this.markerHalfSize );
|
|
2246
|
+
this.intSatMarker.style.top = currentTop + "px";
|
|
2247
|
+
this._positionToSv( currentLeft, currentTop );
|
|
2248
|
+
this._updateColorValue();
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
let innerMouseMove = e => {
|
|
2252
|
+
const dX = e.movementX;
|
|
2253
|
+
const dY = e.movementY;
|
|
2254
|
+
|
|
2255
|
+
const rect = this.colorPickerBackground.getBoundingClientRect();
|
|
2256
|
+
const mouseX = e.offsetX - rect.x;
|
|
2257
|
+
const mouseY = e.offsetY - rect.y;
|
|
2258
|
+
|
|
2259
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.colorPickerBackground.offsetWidth || dX > 0 ) )
|
|
2260
|
+
{
|
|
2261
|
+
this.intSatMarker.style.left = LX.clamp( parseInt( this.intSatMarker.style.left ) + dX, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize ) + "px";
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
if ( dY != 0 && ( mouseY >= 0 || dY < 0 ) && ( mouseY < this.colorPickerBackground.offsetHeight || dY > 0 ) )
|
|
2265
|
+
{
|
|
2266
|
+
this.intSatMarker.style.top = LX.clamp( parseInt( this.intSatMarker.style.top ) + dY, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize ) + "px";
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
this._positionToSv( parseInt( this.intSatMarker.style.left ), parseInt( this.intSatMarker.style.top ) );
|
|
2270
|
+
this._updateColorValue();
|
|
2271
|
+
|
|
2272
|
+
e.stopPropagation();
|
|
2273
|
+
e.preventDefault();
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
let innerMouseUp = e => {
|
|
2277
|
+
var doc = this.root.ownerDocument;
|
|
2278
|
+
doc.removeEventListener( 'mousemove', innerMouseMove );
|
|
2279
|
+
doc.removeEventListener( 'mouseup', innerMouseUp );
|
|
2280
|
+
document.body.classList.remove( 'noevents' );
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
this.colorPickerBackground.addEventListener( "mousedown", innerMouseDown );
|
|
2284
|
+
|
|
2285
|
+
const hueAlphaContainer = LX.makeContainer( ["100%", "auto"], "flex flex-row gap-1 items-center", "", this.root );
|
|
2286
|
+
|
|
2287
|
+
if( window.EyeDropper )
|
|
2288
|
+
{
|
|
2289
|
+
hueAlphaContainer.appendChild( new Button(null, "eyedrop", async () => {
|
|
2290
|
+
const eyeDropper = new EyeDropper()
|
|
2291
|
+
try {
|
|
2292
|
+
const result = await eyeDropper.open();
|
|
2293
|
+
this.fromHexColor( result.sRGBHex );
|
|
2294
|
+
} catch ( err ) {
|
|
2295
|
+
// console.error("EyeDropper cancelled or failed: ", err)
|
|
2296
|
+
}
|
|
2297
|
+
}, { icon: "eye-dropper", buttonClass: "bg-none", title: "Sample Color" }).root );
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
const innerHueAlpha = LX.makeContainer( ["100%", "100%"], "flex flex-col gap-2", "", hueAlphaContainer );
|
|
2301
|
+
|
|
2302
|
+
// Hue
|
|
2303
|
+
this.colorPickerTracker = document.createElement( 'div' );
|
|
2304
|
+
this.colorPickerTracker.className = "lexhuetracker";
|
|
2305
|
+
innerHueAlpha.appendChild( this.colorPickerTracker );
|
|
2306
|
+
|
|
2307
|
+
this.hueMarker = document.createElement( 'div' );
|
|
2308
|
+
this.hueMarker.className = "lexcolormarker";
|
|
2309
|
+
this.hueMarker.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2310
|
+
this.colorPickerTracker.appendChild( this.hueMarker );
|
|
2311
|
+
|
|
2312
|
+
doAsync( () => {
|
|
2313
|
+
const hueLeft = LX.remapRange( this.currentColor.hsv.h, 0, 360, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2314
|
+
this.hueMarker.style.left = hueLeft + "px";
|
|
2315
|
+
} );
|
|
2316
|
+
|
|
2317
|
+
const _fromHueX = ( hueX ) => {
|
|
2318
|
+
this.hueMarker.style.left = hueX + "px";
|
|
2319
|
+
this.currentColor.hsv.h = LX.remapRange( hueX, 0, this.colorPickerTracker.offsetWidth - this.markerSize, 0, 360 );
|
|
2320
|
+
|
|
2321
|
+
const hueColor = new Color( { h: this.currentColor.hsv.h, s: 1, v: 1 } );
|
|
2322
|
+
this.hueMarker.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2323
|
+
this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2324
|
+
this._updateColorValue();
|
|
2325
|
+
};
|
|
2326
|
+
|
|
2327
|
+
let innerMouseDownHue = e => {
|
|
2328
|
+
const doc = this.root.ownerDocument;
|
|
2329
|
+
doc.addEventListener( 'mousemove', innerMouseMoveHue );
|
|
2330
|
+
doc.addEventListener( 'mouseup', innerMouseUpHue );
|
|
2331
|
+
document.body.classList.add( 'noevents' );
|
|
2332
|
+
e.stopImmediatePropagation();
|
|
2333
|
+
e.stopPropagation();
|
|
2334
|
+
|
|
2335
|
+
const hueX = clamp( e.offsetX - this.markerHalfSize, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2336
|
+
_fromHueX( hueX );
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
let innerMouseMoveHue = e => {
|
|
2340
|
+
let dX = e.movementX;
|
|
2341
|
+
|
|
2342
|
+
const rect = this.colorPickerTracker.getBoundingClientRect();
|
|
2343
|
+
const mouseX = e.offsetX - rect.x;
|
|
2344
|
+
|
|
2345
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.colorPickerTracker.offsetWidth || dX > 0 ) )
|
|
2346
|
+
{
|
|
2347
|
+
const hueX = LX.clamp( parseInt( this.hueMarker.style.left ) + dX, 0, this.colorPickerTracker.offsetWidth - this.markerSize );
|
|
2348
|
+
_fromHueX( hueX )
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
e.stopPropagation();
|
|
2352
|
+
e.preventDefault();
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
let innerMouseUpHue = e => {
|
|
2356
|
+
var doc = this.root.ownerDocument;
|
|
2357
|
+
doc.removeEventListener( 'mousemove', innerMouseMoveHue );
|
|
2358
|
+
doc.removeEventListener( 'mouseup', innerMouseUpHue );
|
|
2359
|
+
document.body.classList.remove( 'noevents' );
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2362
|
+
this.colorPickerTracker.addEventListener( "mousedown", innerMouseDownHue );
|
|
2363
|
+
|
|
2364
|
+
// Alpha
|
|
2365
|
+
if( this.useAlpha )
|
|
2366
|
+
{
|
|
2367
|
+
this.alphaTracker = document.createElement( 'div' );
|
|
2368
|
+
this.alphaTracker.className = "lexalphatracker";
|
|
2369
|
+
this.alphaTracker.style.color = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b })`;
|
|
2370
|
+
innerHueAlpha.appendChild( this.alphaTracker );
|
|
2371
|
+
|
|
2372
|
+
this.alphaMarker = document.createElement( 'div' );
|
|
2373
|
+
this.alphaMarker.className = "lexcolormarker";
|
|
2374
|
+
this.alphaMarker.style.backgroundColor = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2375
|
+
this.alphaTracker.appendChild( this.alphaMarker );
|
|
2376
|
+
|
|
2377
|
+
doAsync( () => {
|
|
2378
|
+
const alphaLeft = LX.remapRange( this.currentColor.hsv.a, 0, 1, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2379
|
+
this.alphaMarker.style.left = alphaLeft + "px";
|
|
2380
|
+
} );
|
|
2381
|
+
|
|
2382
|
+
const _fromAlphaX = ( alphaX ) => {
|
|
2383
|
+
this.alphaMarker.style.left = alphaX + "px";
|
|
2384
|
+
this.currentColor.hsv.a = LX.remapRange( alphaX, 0, this.alphaTracker.offsetWidth - this.markerSize, 0, 1 );
|
|
2385
|
+
this._updateColorValue();
|
|
2386
|
+
// Update alpha marker once the color is updated
|
|
2387
|
+
this.alphaMarker.style.backgroundColor = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2388
|
+
};
|
|
2389
|
+
|
|
2390
|
+
let innerMouseDownAlpha = e => {
|
|
2391
|
+
const doc = this.root.ownerDocument;
|
|
2392
|
+
doc.addEventListener( 'mousemove', innerMouseMoveAlpha );
|
|
2393
|
+
doc.addEventListener( 'mouseup', innerMouseUpAlpha );
|
|
2394
|
+
document.body.classList.add( 'noevents' );
|
|
2395
|
+
e.stopImmediatePropagation();
|
|
2396
|
+
e.stopPropagation();
|
|
2397
|
+
const alphaX = clamp( e.offsetX - this.markerHalfSize, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2398
|
+
_fromAlphaX( alphaX );
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
let innerMouseMoveAlpha = e => {
|
|
2402
|
+
let dX = e.movementX;
|
|
2403
|
+
|
|
2404
|
+
const rect = this.alphaTracker.getBoundingClientRect();
|
|
2405
|
+
const mouseX = e.offsetX - rect.x;
|
|
2406
|
+
|
|
2407
|
+
if ( dX != 0 && ( mouseX >= 0 || dX < 0 ) && ( mouseX < this.alphaTracker.offsetWidth || dX > 0 ) )
|
|
2408
|
+
{
|
|
2409
|
+
const alphaX = LX.clamp( parseInt( this.alphaMarker.style.left ) + dX, 0, this.alphaTracker.offsetWidth - this.markerSize );
|
|
2410
|
+
_fromAlphaX( alphaX );
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
e.stopPropagation();
|
|
2414
|
+
e.preventDefault();
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
let innerMouseUpAlpha = e => {
|
|
2418
|
+
var doc = this.root.ownerDocument;
|
|
2419
|
+
doc.removeEventListener( 'mousemove', innerMouseMoveAlpha );
|
|
2420
|
+
doc.removeEventListener( 'mouseup', innerMouseUpAlpha );
|
|
2421
|
+
document.body.classList.remove( 'noevents' );
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
this.alphaTracker.addEventListener( "mousedown", innerMouseDownAlpha );
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
// Info display
|
|
2428
|
+
const colorLabel = LX.makeContainer( ["100%", "auto"], "flex flex-row gap-1", "", this.root );
|
|
2429
|
+
|
|
2430
|
+
colorLabel.appendChild( new Select( null, [ "CSS", "Hex", "HSV", "RGB" ], this.colorModel, v => {
|
|
2431
|
+
this.colorModel = v;
|
|
2432
|
+
this._updateColorValue( null, true );
|
|
2433
|
+
} ).root );
|
|
2434
|
+
|
|
2435
|
+
this.labelWidget = new TextInput( null, "", null, { inputClass: "bg-none", fit: true, disabled: true } );
|
|
2436
|
+
colorLabel.appendChild( this.labelWidget.root );
|
|
2437
|
+
|
|
2438
|
+
colorLabel.appendChild( new Button(null, "eyedrop", async () => {
|
|
2439
|
+
navigator.clipboard.writeText( this.labelWidget.value() );
|
|
2440
|
+
}, { icon: "copy", buttonClass: "bg-none", className: "ml-auto", title: "Copy" }).root );
|
|
2441
|
+
|
|
2442
|
+
this._updateColorValue( hexValue, true );
|
|
2443
|
+
|
|
2444
|
+
doAsync( () => {
|
|
2445
|
+
this._adjustPosition();
|
|
2446
|
+
|
|
2447
|
+
this.root.focus();
|
|
2448
|
+
|
|
2449
|
+
this._onClick = e => {
|
|
2450
|
+
if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
|
|
2451
|
+
{
|
|
2452
|
+
return;
|
|
2453
|
+
}
|
|
2454
|
+
this.destroy();
|
|
2455
|
+
};
|
|
2456
|
+
|
|
2457
|
+
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
2458
|
+
document.body.addEventListener( "focusin", this._onClick, true );
|
|
2459
|
+
}, 10 );
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
fromHexColor( hexColor ) {
|
|
2463
|
+
|
|
2464
|
+
this.currentColor.setHex( hexColor );
|
|
2465
|
+
|
|
2466
|
+
// Decompose into HSV
|
|
2467
|
+
const { h, s, v } = this.currentColor.hsv;
|
|
2468
|
+
this._svToPosition( s, v );
|
|
2469
|
+
|
|
2470
|
+
const hueColor = new Color( { h, s: 1, v: 1 } );
|
|
2471
|
+
this.hueMarker.style.backgroundColor = this.colorPickerBackground.style.backgroundColor = `rgb(${ hueColor.css.r }, ${ hueColor.css.g }, ${ hueColor.css.b })`;
|
|
2472
|
+
this.hueMarker.style.left = LX.remapRange( h, 0, 360, -this.markerHalfSize, this.colorPickerTracker.offsetWidth - this.markerHalfSize ) + "px";
|
|
2473
|
+
|
|
2474
|
+
this._updateColorValue( hexColor );
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
destroy() {
|
|
2478
|
+
|
|
2479
|
+
this._trigger.classList.remove( "triggered" );
|
|
2480
|
+
|
|
2481
|
+
delete this._trigger.picker;
|
|
2482
|
+
|
|
2483
|
+
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
2484
|
+
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
2485
|
+
|
|
2486
|
+
LX.root.querySelectorAll( ".lexcolorpicker" ).forEach( m => { m.remove(); } );
|
|
2487
|
+
|
|
2488
|
+
ColorPicker.currentPicker = null;
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
_svToPosition( s, v ) {
|
|
2492
|
+
this.intSatMarker.style.left = `${ LX.remapRange( s, 0, 1, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize ) }px`;
|
|
2493
|
+
this.intSatMarker.style.top = `${ LX.remapRange( 1 - v, 0, 1, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize ) }px`
|
|
2494
|
+
};
|
|
2495
|
+
|
|
2496
|
+
_positionToSv( left, top ) {
|
|
2497
|
+
this.currentColor.hsv.s = LX.remapRange( left, -this.markerHalfSize, this.colorPickerBackground.offsetWidth - this.markerHalfSize, 0, 1 );
|
|
2498
|
+
this.currentColor.hsv.v = 1 - LX.remapRange( top, -this.markerHalfSize, this.colorPickerBackground.offsetHeight - this.markerHalfSize, 0, 1 );
|
|
2499
|
+
};
|
|
2500
|
+
|
|
2501
|
+
_updateColorValue( newHexValue, skipCallback = false ) {
|
|
1840
2502
|
|
|
1841
|
-
|
|
2503
|
+
this.currentColor.set( newHexValue ?? this.currentColor.hsv );
|
|
1842
2504
|
|
|
1843
|
-
|
|
1844
|
-
|
|
2505
|
+
if( this.callback && !skipCallback )
|
|
2506
|
+
{
|
|
2507
|
+
this.callback( this.currentColor );
|
|
2508
|
+
}
|
|
1845
2509
|
|
|
1846
|
-
|
|
1847
|
-
{
|
|
1848
|
-
path += "/" + p.id;
|
|
1849
|
-
p = p.currentParent?.parentElement;
|
|
1850
|
-
}
|
|
2510
|
+
this.intSatMarker.style.backgroundColor = this.currentColor.hex;
|
|
1851
2511
|
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
m.remove();
|
|
1857
|
-
}
|
|
1858
|
-
} );
|
|
2512
|
+
if( this.useAlpha )
|
|
2513
|
+
{
|
|
2514
|
+
this.alphaTracker.style.color = `rgb(${ this.currentColor.css.r }, ${ this.currentColor.css.g }, ${ this.currentColor.css.b },${ this.currentColor.css.a })`;
|
|
2515
|
+
}
|
|
1859
2516
|
|
|
1860
|
-
|
|
1861
|
-
{
|
|
1862
|
-
if( menuItem.built )
|
|
1863
|
-
{
|
|
1864
|
-
return;
|
|
1865
|
-
}
|
|
1866
|
-
menuItem.built = true;
|
|
1867
|
-
this._create( item.submenu, menuItem );
|
|
1868
|
-
}
|
|
2517
|
+
const toFixed = ( s, n = 2) => { return s.toFixed( n ).replace( /([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1' ) };
|
|
1869
2518
|
|
|
1870
|
-
|
|
1871
|
-
|
|
2519
|
+
if( this.colorModel == "CSS" )
|
|
2520
|
+
{
|
|
2521
|
+
const { r, g, b, a } = this.currentColor.css;
|
|
2522
|
+
this.labelWidget.set( `rgba(${ r },${ g },${ b }${ this.useAlpha ? ',' + toFixed( a ) : '' })` );
|
|
1872
2523
|
}
|
|
1873
|
-
|
|
2524
|
+
else if( this.colorModel == "Hex" )
|
|
2525
|
+
{
|
|
2526
|
+
this.labelWidget.set( ( this.useAlpha ? this.currentColor.hex : this.currentColor.hex.substr( 0, 7 ) ).toUpperCase() );
|
|
2527
|
+
}
|
|
2528
|
+
else if( this.colorModel == "HSV" )
|
|
2529
|
+
{
|
|
2530
|
+
const { h, s, v, a } = this.currentColor.hsv;
|
|
2531
|
+
const components = [ Math.floor( h ) + 'º', Math.floor( s * 100 ) + '%', Math.floor( v * 100 ) + '%' ];
|
|
2532
|
+
if( this.useAlpha ) components.push( toFixed( a ) );
|
|
2533
|
+
this.labelWidget.set( components.join( ' ' ) );
|
|
2534
|
+
}
|
|
2535
|
+
else // RGB
|
|
2536
|
+
{
|
|
2537
|
+
const { r, g, b, a } = this.currentColor.rgb;
|
|
2538
|
+
const components = [ toFixed( r ), toFixed( g ), toFixed( b ) ];
|
|
2539
|
+
if( this.useAlpha ) components.push( toFixed( a ) );
|
|
2540
|
+
this.labelWidget.set( components.join( ' ' ) );
|
|
2541
|
+
}
|
|
2542
|
+
};
|
|
1874
2543
|
|
|
1875
2544
|
_adjustPosition() {
|
|
1876
2545
|
|
|
@@ -1932,16 +2601,9 @@ class DropdownMenu {
|
|
|
1932
2601
|
this.root.style.left = `${ position[ 0 ] }px`;
|
|
1933
2602
|
this.root.style.top = `${ position[ 1 ] }px`;
|
|
1934
2603
|
}
|
|
1935
|
-
|
|
1936
|
-
_addSeparator( parent ) {
|
|
1937
|
-
const separator = document.createElement('div');
|
|
1938
|
-
separator.className = "separator";
|
|
1939
|
-
parent = parent ?? this.root;
|
|
1940
|
-
parent.appendChild( separator );
|
|
1941
|
-
}
|
|
1942
2604
|
};
|
|
1943
2605
|
|
|
1944
|
-
LX.
|
|
2606
|
+
LX.ColorPicker = ColorPicker;
|
|
1945
2607
|
|
|
1946
2608
|
class Area {
|
|
1947
2609
|
|
|
@@ -3804,57 +4466,14 @@ class Menubar {
|
|
|
3804
4466
|
|
|
3805
4467
|
for( let i = 0; i < buttons.length; ++i )
|
|
3806
4468
|
{
|
|
3807
|
-
|
|
3808
|
-
let button = document.createElement( "label" );
|
|
4469
|
+
const data = buttons[ i ];
|
|
3809
4470
|
const title = data.title;
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
button.title = title ?? "";
|
|
3813
|
-
this.buttonContainer.appendChild( button );
|
|
3814
|
-
|
|
3815
|
-
const icon = document.createElement( "a" );
|
|
3816
|
-
icon.className = data.icon + " lexicon";
|
|
3817
|
-
button.appendChild( icon );
|
|
3818
|
-
|
|
3819
|
-
let trigger = icon;
|
|
3820
|
-
|
|
3821
|
-
if( data.swap )
|
|
3822
|
-
{
|
|
3823
|
-
button.classList.add( "swap" );
|
|
3824
|
-
icon.classList.add( "swap-off" );
|
|
3825
|
-
|
|
3826
|
-
const input = document.createElement( "input" );
|
|
3827
|
-
input.type = "checkbox";
|
|
3828
|
-
button.prepend( input );
|
|
3829
|
-
trigger = input;
|
|
3830
|
-
|
|
3831
|
-
const swapIcon = document.createElement( "a" );
|
|
3832
|
-
swapIcon.className = data.swap + " swap-on lexicon";
|
|
3833
|
-
button.appendChild( swapIcon );
|
|
3834
|
-
|
|
3835
|
-
button.swap = function() {
|
|
3836
|
-
const swapInput = this.querySelector( "input" );
|
|
3837
|
-
swapInput.checked = !swapInput.checked;
|
|
3838
|
-
};
|
|
3839
|
-
|
|
3840
|
-
// Set if swap has to be performed
|
|
3841
|
-
button.setState = function( v ) {
|
|
3842
|
-
const swapInput = this.querySelector( "input" );
|
|
3843
|
-
swapInput.checked = v;
|
|
3844
|
-
};
|
|
3845
|
-
}
|
|
3846
|
-
|
|
3847
|
-
trigger.addEventListener("click", e => {
|
|
3848
|
-
if( data.callback && !disabled )
|
|
3849
|
-
{
|
|
3850
|
-
const swapInput = button.querySelector( "input" );
|
|
3851
|
-
data.callback.call( this, e, swapInput?.checked );
|
|
3852
|
-
}
|
|
3853
|
-
});
|
|
4471
|
+
const button = new Button( title, "", data.callback, { title, buttonClass: "bg-none", disabled: data.disabled, icon: data.icon, hideName: true, swap: data.swap } )
|
|
4472
|
+
this.buttonContainer.appendChild( button.root );
|
|
3854
4473
|
|
|
3855
4474
|
if( title )
|
|
3856
4475
|
{
|
|
3857
|
-
this.buttons[ title ] = button;
|
|
4476
|
+
this.buttons[ title ] = button.root;
|
|
3858
4477
|
}
|
|
3859
4478
|
}
|
|
3860
4479
|
}
|
|
@@ -4557,14 +5176,15 @@ class Widget {
|
|
|
4557
5176
|
static SEPARATOR = 26;
|
|
4558
5177
|
static KNOB = 27;
|
|
4559
5178
|
static SIZE = 28;
|
|
4560
|
-
static
|
|
4561
|
-
static
|
|
4562
|
-
static
|
|
4563
|
-
static
|
|
4564
|
-
static
|
|
4565
|
-
static
|
|
4566
|
-
static
|
|
4567
|
-
static
|
|
5179
|
+
static OTP = 29;
|
|
5180
|
+
static PAD = 30;
|
|
5181
|
+
static FORM = 31;
|
|
5182
|
+
static DIAL = 32;
|
|
5183
|
+
static COUNTER = 33;
|
|
5184
|
+
static TABLE = 34;
|
|
5185
|
+
static TABS = 35;
|
|
5186
|
+
static LABEL = 36;
|
|
5187
|
+
static BLANK = 37;
|
|
4568
5188
|
|
|
4569
5189
|
static NO_CONTEXT_TYPES = [
|
|
4570
5190
|
Widget.BUTTON,
|
|
@@ -5809,40 +6429,17 @@ class Button extends Widget {
|
|
|
5809
6429
|
super( Widget.BUTTON, name, null, options );
|
|
5810
6430
|
|
|
5811
6431
|
this.onGetValue = () => {
|
|
5812
|
-
return wValue.
|
|
6432
|
+
return wValue.querySelector( "input" )?.checked;
|
|
5813
6433
|
};
|
|
5814
6434
|
|
|
5815
6435
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
5816
6436
|
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
if( options.icon )
|
|
5820
|
-
{
|
|
5821
|
-
let icon = null;
|
|
5822
|
-
|
|
5823
|
-
// @legacy
|
|
5824
|
-
if( options.icon.includes( "fa-" ) )
|
|
5825
|
-
{
|
|
5826
|
-
icon = document.createElement( 'a' );
|
|
5827
|
-
icon.className = options.icon;
|
|
5828
|
-
}
|
|
5829
|
-
else
|
|
5830
|
-
{
|
|
5831
|
-
icon = LX.makeIcon( options.icon );
|
|
5832
|
-
}
|
|
5833
|
-
|
|
5834
|
-
wValue.prepend( icon );
|
|
5835
|
-
}
|
|
5836
|
-
else if( options.img )
|
|
6437
|
+
if( !( options.swap ?? false ) )
|
|
5837
6438
|
{
|
|
5838
|
-
|
|
5839
|
-
img.src = options.img;
|
|
5840
|
-
wValue.prepend( img );
|
|
5841
|
-
}
|
|
5842
|
-
else
|
|
5843
|
-
{
|
|
5844
|
-
wValue.innerHTML = `<span>${ ( newValue || "" ) }</span>`;
|
|
6439
|
+
return;
|
|
5845
6440
|
}
|
|
6441
|
+
|
|
6442
|
+
this.root.setState( newValue, skipCallback );
|
|
5846
6443
|
};
|
|
5847
6444
|
|
|
5848
6445
|
this.onResize = ( rect ) => {
|
|
@@ -5866,25 +6463,88 @@ class Button extends Widget {
|
|
|
5866
6463
|
wValue.classList.add( "selected" );
|
|
5867
6464
|
}
|
|
5868
6465
|
|
|
5869
|
-
|
|
6466
|
+
if( options.icon )
|
|
6467
|
+
{
|
|
6468
|
+
let icon = null;
|
|
6469
|
+
|
|
6470
|
+
// @legacy
|
|
6471
|
+
if( options.icon.includes( "fa-" ) )
|
|
6472
|
+
{
|
|
6473
|
+
icon = document.createElement( 'a' );
|
|
6474
|
+
icon.className = options.icon + " lexicon";
|
|
6475
|
+
}
|
|
6476
|
+
else
|
|
6477
|
+
{
|
|
6478
|
+
icon = LX.makeIcon( options.icon );
|
|
6479
|
+
}
|
|
6480
|
+
|
|
6481
|
+
wValue.prepend( icon );
|
|
6482
|
+
}
|
|
6483
|
+
else if( options.img )
|
|
6484
|
+
{
|
|
6485
|
+
let img = document.createElement( 'img' );
|
|
6486
|
+
img.src = options.img;
|
|
6487
|
+
wValue.prepend( img );
|
|
6488
|
+
}
|
|
6489
|
+
else
|
|
6490
|
+
{
|
|
6491
|
+
wValue.innerHTML = `<span>${ ( value || "" ) }</span>`;
|
|
6492
|
+
}
|
|
5870
6493
|
|
|
5871
6494
|
if( options.disabled )
|
|
5872
6495
|
{
|
|
5873
6496
|
wValue.setAttribute( "disabled", true );
|
|
5874
6497
|
}
|
|
5875
6498
|
|
|
5876
|
-
|
|
6499
|
+
let trigger = wValue;
|
|
6500
|
+
|
|
6501
|
+
if( options.swap )
|
|
6502
|
+
{
|
|
6503
|
+
wValue.classList.add( "swap" );
|
|
6504
|
+
wValue.querySelector( "a" ).classList.add( "swap-off" );
|
|
6505
|
+
|
|
6506
|
+
const input = document.createElement( "input" );
|
|
6507
|
+
input.type = "checkbox";
|
|
6508
|
+
wValue.prepend( input );
|
|
6509
|
+
// trigger = input;
|
|
6510
|
+
|
|
6511
|
+
const swapIcon = document.createElement( "a" );
|
|
6512
|
+
swapIcon.className = options.swap + " swap-on lexicon";
|
|
6513
|
+
wValue.appendChild( swapIcon );
|
|
6514
|
+
|
|
6515
|
+
this.root.swap = function( skipCallback ) {
|
|
6516
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6517
|
+
swapInput.checked = !swapInput.checked;
|
|
6518
|
+
if( !skipCallback )
|
|
6519
|
+
{
|
|
6520
|
+
trigger.click();
|
|
6521
|
+
}
|
|
6522
|
+
};
|
|
6523
|
+
|
|
6524
|
+
// Set if swap has to be performed
|
|
6525
|
+
this.root.setState = function( v, skipCallback ) {
|
|
6526
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6527
|
+
swapInput.checked = v;
|
|
6528
|
+
if( !skipCallback )
|
|
6529
|
+
{
|
|
6530
|
+
trigger.click();
|
|
6531
|
+
}
|
|
6532
|
+
};
|
|
6533
|
+
}
|
|
6534
|
+
|
|
6535
|
+
trigger.addEventListener( "click", e => {
|
|
5877
6536
|
if( options.selectable )
|
|
5878
6537
|
{
|
|
5879
6538
|
if( options.parent )
|
|
5880
6539
|
{
|
|
5881
|
-
options.parent.querySelectorAll(".lexbutton.selected").forEach(
|
|
6540
|
+
options.parent.querySelectorAll(".lexbutton.selected").forEach( b => { if( b == wValue ) return; b.classList.remove( "selected" ) } );
|
|
5882
6541
|
}
|
|
5883
6542
|
|
|
5884
6543
|
wValue.classList.toggle('selected');
|
|
5885
6544
|
}
|
|
5886
6545
|
|
|
5887
|
-
|
|
6546
|
+
const swapInput = wValue.querySelector( "input" );
|
|
6547
|
+
this._trigger( new IEvent( name, swapInput?.checked ?? value, e ), callback );
|
|
5888
6548
|
});
|
|
5889
6549
|
|
|
5890
6550
|
if( options.tooltip )
|
|
@@ -6279,7 +6939,7 @@ class Select extends Widget {
|
|
|
6279
6939
|
|
|
6280
6940
|
const selectRoot = selectedOption.root;
|
|
6281
6941
|
const rect = selectRoot.getBoundingClientRect();
|
|
6282
|
-
const nestedDialog = parent.parentElement.closest( "dialog" );
|
|
6942
|
+
const nestedDialog = parent.parentElement.closest( "dialog" ) ?? parent.parentElement.closest( ".lexcolorpicker" );
|
|
6283
6943
|
|
|
6284
6944
|
// Manage vertical aspect
|
|
6285
6945
|
{
|
|
@@ -7329,31 +7989,52 @@ class ColorInput extends Widget {
|
|
|
7329
7989
|
|
|
7330
7990
|
constructor( name, value, callback, options = {} ) {
|
|
7331
7991
|
|
|
7332
|
-
|
|
7992
|
+
const useAlpha = options.useAlpha ??
|
|
7993
|
+
( ( value.constructor === Object && 'a' in value ) || ( value.constructor === String && [ 5, 9 ].includes( value.length ) ) );
|
|
7994
|
+
|
|
7995
|
+
const widgetColor = new Color( value );
|
|
7996
|
+
|
|
7997
|
+
// Force always hex internally
|
|
7998
|
+
value = useAlpha ? widgetColor.hex : widgetColor.hex.substr( 0, 7 );
|
|
7333
7999
|
|
|
7334
8000
|
super( Widget.COLOR, name, value, options );
|
|
7335
8001
|
|
|
7336
8002
|
this.onGetValue = () => {
|
|
7337
|
-
|
|
8003
|
+
const currentColor = new Color( value );
|
|
8004
|
+
return options.useRGB ? currentColor.rgb : value;
|
|
7338
8005
|
};
|
|
7339
8006
|
|
|
7340
8007
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
7341
8008
|
|
|
7342
|
-
|
|
8009
|
+
const newColor = new Color( newValue );
|
|
8010
|
+
|
|
8011
|
+
colorSampleRGB.style.color = value = newColor.hex.substr( 0, 7 );
|
|
8012
|
+
|
|
8013
|
+
if( useAlpha )
|
|
7343
8014
|
{
|
|
7344
|
-
|
|
8015
|
+
colorSampleAlpha.style.color = value = newColor.hex;
|
|
7345
8016
|
}
|
|
7346
8017
|
|
|
7347
8018
|
if( !this._skipTextUpdate )
|
|
7348
8019
|
{
|
|
7349
|
-
textWidget.set(
|
|
8020
|
+
textWidget.set( value, true, event );
|
|
7350
8021
|
}
|
|
7351
8022
|
|
|
7352
|
-
color.value = value = newValue;
|
|
7353
|
-
|
|
7354
8023
|
if( !skipCallback )
|
|
7355
8024
|
{
|
|
7356
|
-
|
|
8025
|
+
let retValue = value;
|
|
8026
|
+
|
|
8027
|
+
if( options.useRGB )
|
|
8028
|
+
{
|
|
8029
|
+
retValue = newColor.rgb;
|
|
8030
|
+
|
|
8031
|
+
if( !useAlpha )
|
|
8032
|
+
{
|
|
8033
|
+
delete retValue.a;
|
|
8034
|
+
}
|
|
8035
|
+
}
|
|
8036
|
+
|
|
8037
|
+
this._trigger( new IEvent( name, retValue, event ), callback );
|
|
7357
8038
|
}
|
|
7358
8039
|
};
|
|
7359
8040
|
|
|
@@ -7366,30 +8047,50 @@ class ColorInput extends Widget {
|
|
|
7366
8047
|
container.className = "lexcolor";
|
|
7367
8048
|
this.root.appendChild( container );
|
|
7368
8049
|
|
|
7369
|
-
let
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
8050
|
+
let sampleContainer = LX.makeContainer( ["18px", "18px"], "flex flex-row bg-contrast rounded overflow-hidden", "", container );
|
|
8051
|
+
sampleContainer.tabIndex = "1";
|
|
8052
|
+
sampleContainer.addEventListener( "click", e => {
|
|
8053
|
+
if( ( options.disabled ?? false ) )
|
|
8054
|
+
{
|
|
8055
|
+
return;
|
|
8056
|
+
}
|
|
8057
|
+
new ColorPicker( value, sampleContainer, {
|
|
8058
|
+
colorModel: options.useRGB ? "RGB" : "Hex",
|
|
8059
|
+
useAlpha,
|
|
8060
|
+
onChange: ( color ) => {
|
|
8061
|
+
this._fromColorPicker = true;
|
|
8062
|
+
this.set( color.hex );
|
|
8063
|
+
delete this._fromColorPicker;
|
|
8064
|
+
}
|
|
8065
|
+
} );
|
|
8066
|
+
} );
|
|
8067
|
+
|
|
8068
|
+
let colorSampleRGB = document.createElement( 'div' );
|
|
8069
|
+
colorSampleRGB.className = "lexcolorsample";
|
|
8070
|
+
colorSampleRGB.style.color = value;
|
|
8071
|
+
sampleContainer.appendChild( colorSampleRGB );
|
|
7376
8072
|
|
|
7377
|
-
|
|
8073
|
+
let colorSampleAlpha = null;
|
|
8074
|
+
|
|
8075
|
+
if( useAlpha )
|
|
7378
8076
|
{
|
|
7379
|
-
|
|
8077
|
+
colorSampleAlpha = document.createElement( 'div' );
|
|
8078
|
+
colorSampleAlpha.className = "lexcolorsample";
|
|
8079
|
+
colorSampleAlpha.style.color = value;
|
|
8080
|
+
sampleContainer.appendChild( colorSampleAlpha );
|
|
8081
|
+
}
|
|
8082
|
+
else
|
|
8083
|
+
{
|
|
8084
|
+
colorSampleRGB.style.width = "18px";
|
|
7380
8085
|
}
|
|
7381
8086
|
|
|
7382
|
-
|
|
7383
|
-
this.set( e.target.value, false, e );
|
|
7384
|
-
}, false );
|
|
7385
|
-
|
|
7386
|
-
const textWidget = new TextInput( null, color.value, v => {
|
|
8087
|
+
const textWidget = new TextInput( null, value, v => {
|
|
7387
8088
|
this._skipTextUpdate = true;
|
|
7388
8089
|
this.set( v );
|
|
7389
8090
|
delete this._skipTextUpdate;
|
|
7390
|
-
}, { width: "calc( 100% -
|
|
8091
|
+
}, { width: "calc( 100% - 24px )", disabled: options.disabled });
|
|
7391
8092
|
|
|
7392
|
-
textWidget.root.style.marginLeft = "
|
|
8093
|
+
textWidget.root.style.marginLeft = "6px";
|
|
7393
8094
|
container.appendChild( textWidget.root );
|
|
7394
8095
|
|
|
7395
8096
|
doAsync( this.onResize.bind( this ) );
|
|
@@ -8097,6 +8798,164 @@ class SizeInput extends Widget {
|
|
|
8097
8798
|
|
|
8098
8799
|
LX.SizeInput = SizeInput;
|
|
8099
8800
|
|
|
8801
|
+
/**
|
|
8802
|
+
* @class OTPInput
|
|
8803
|
+
* @description OTPInput Widget
|
|
8804
|
+
*/
|
|
8805
|
+
|
|
8806
|
+
class OTPInput extends Widget {
|
|
8807
|
+
|
|
8808
|
+
constructor( name, value, callback, options = {} ) {
|
|
8809
|
+
|
|
8810
|
+
const pattern = options.pattern ?? "xxx-xxx";
|
|
8811
|
+
const patternSize = ( pattern.match(/x/g) || [] ).length;
|
|
8812
|
+
|
|
8813
|
+
value = String( value );
|
|
8814
|
+
if( !value.length )
|
|
8815
|
+
{
|
|
8816
|
+
value = "x".repeat( patternSize );
|
|
8817
|
+
}
|
|
8818
|
+
|
|
8819
|
+
super( Widget.OTP, name, value, options );
|
|
8820
|
+
|
|
8821
|
+
this.onGetValue = () => {
|
|
8822
|
+
return +value;
|
|
8823
|
+
};
|
|
8824
|
+
|
|
8825
|
+
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
8826
|
+
|
|
8827
|
+
value = newValue;
|
|
8828
|
+
|
|
8829
|
+
_refreshInput( value );
|
|
8830
|
+
|
|
8831
|
+
if( !skipCallback )
|
|
8832
|
+
{
|
|
8833
|
+
this._trigger( new IEvent( name, +newValue, event ), callback );
|
|
8834
|
+
}
|
|
8835
|
+
};
|
|
8836
|
+
|
|
8837
|
+
this.onResize = ( rect ) => {
|
|
8838
|
+
const realNameWidth = ( this.root.domName?.offsetWidth ?? 0 );
|
|
8839
|
+
container.style.width = `calc( 100% - ${ realNameWidth }px)`;
|
|
8840
|
+
};
|
|
8841
|
+
|
|
8842
|
+
this.disabled = options.disabled ?? false;
|
|
8843
|
+
|
|
8844
|
+
const container = document.createElement( 'div' );
|
|
8845
|
+
container.className = "lexotp flex flex-row items-center";
|
|
8846
|
+
this.root.appendChild( container );
|
|
8847
|
+
|
|
8848
|
+
const groups = pattern.split( '-' );
|
|
8849
|
+
|
|
8850
|
+
const _refreshInput = ( valueString ) => {
|
|
8851
|
+
|
|
8852
|
+
container.innerHTML = "";
|
|
8853
|
+
|
|
8854
|
+
let itemsCount = 0;
|
|
8855
|
+
let activeSlot = 0;
|
|
8856
|
+
|
|
8857
|
+
for( let i = 0; i < groups.length; ++i )
|
|
8858
|
+
{
|
|
8859
|
+
const g = groups[ i ];
|
|
8860
|
+
|
|
8861
|
+
for( let j = 0; j < g.length; ++j )
|
|
8862
|
+
{
|
|
8863
|
+
let number = valueString[ itemsCount++ ];
|
|
8864
|
+
number = ( number == 'x' ? '' : number );
|
|
8865
|
+
|
|
8866
|
+
const slotDom = LX.makeContainer( ["36px", "30px"],
|
|
8867
|
+
"lexotpslot border-top border-bottom border-left px-3 cursor-text select-none font-medium outline-none", number, container );
|
|
8868
|
+
slotDom.tabIndex = "1";
|
|
8869
|
+
|
|
8870
|
+
if( this.disabled )
|
|
8871
|
+
{
|
|
8872
|
+
slotDom.classList.add( "disabled" );
|
|
8873
|
+
}
|
|
8874
|
+
|
|
8875
|
+
const otpIndex = itemsCount;
|
|
8876
|
+
|
|
8877
|
+
if( j == 0 )
|
|
8878
|
+
{
|
|
8879
|
+
slotDom.className += " rounded-l";
|
|
8880
|
+
}
|
|
8881
|
+
else if( j == ( g.length - 1 ) )
|
|
8882
|
+
{
|
|
8883
|
+
slotDom.className += " rounded-r border-right";
|
|
8884
|
+
}
|
|
8885
|
+
|
|
8886
|
+
slotDom.addEventListener( "click", () => {
|
|
8887
|
+
if( this.disabled ) { return; }
|
|
8888
|
+
container.querySelectorAll( ".lexotpslot" ).forEach( s => s.classList.remove( "active" ) );
|
|
8889
|
+
const activeDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot ];
|
|
8890
|
+
activeDom.classList.add( "active" );
|
|
8891
|
+
activeDom.focus();
|
|
8892
|
+
} );
|
|
8893
|
+
|
|
8894
|
+
slotDom.addEventListener( "blur", () => {
|
|
8895
|
+
if( this.disabled ) { return; }
|
|
8896
|
+
doAsync( () => {
|
|
8897
|
+
if( container.contains( document.activeElement ) ) { return; }
|
|
8898
|
+
container.querySelectorAll( ".lexotpslot" ).forEach( s => s.classList.remove( "active" ) );
|
|
8899
|
+
}, 10 );
|
|
8900
|
+
} );
|
|
8901
|
+
|
|
8902
|
+
slotDom.addEventListener( "keyup", e => {
|
|
8903
|
+
if( this.disabled ) { return; }
|
|
8904
|
+
if( !/[^0-9]+/g.test( e.key ) )
|
|
8905
|
+
{
|
|
8906
|
+
const number = e.key;
|
|
8907
|
+
console.assert( parseInt( number ) != NaN );
|
|
8908
|
+
|
|
8909
|
+
slotDom.innerHTML = number;
|
|
8910
|
+
valueString = valueString.substring( 0, otpIndex - 1 ) + number + valueString.substring( otpIndex );
|
|
8911
|
+
|
|
8912
|
+
const nexActiveDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot + 1 ];
|
|
8913
|
+
if( nexActiveDom )
|
|
8914
|
+
{
|
|
8915
|
+
container.querySelectorAll( ".lexotpslot" )[ activeSlot ].classList.remove( "active" );
|
|
8916
|
+
nexActiveDom.classList.add( "active" );
|
|
8917
|
+
nexActiveDom.focus();
|
|
8918
|
+
activeSlot++;
|
|
8919
|
+
}
|
|
8920
|
+
else
|
|
8921
|
+
{
|
|
8922
|
+
this.set( valueString );
|
|
8923
|
+
}
|
|
8924
|
+
}
|
|
8925
|
+
else if( e.key == "ArrowLeft" || e.key == "ArrowRight" )
|
|
8926
|
+
{
|
|
8927
|
+
const dt = ( e.key == "ArrowLeft" ) ? -1 : 1;
|
|
8928
|
+
const newActiveDom = container.querySelectorAll( ".lexotpslot" )[ activeSlot + dt ];
|
|
8929
|
+
if( newActiveDom )
|
|
8930
|
+
{
|
|
8931
|
+
container.querySelectorAll( ".lexotpslot" )[ activeSlot ].classList.remove( "active" );
|
|
8932
|
+
newActiveDom.classList.add( "active" );
|
|
8933
|
+
newActiveDom.focus();
|
|
8934
|
+
activeSlot += dt;
|
|
8935
|
+
}
|
|
8936
|
+
}
|
|
8937
|
+
else if( e.key == "Enter" && !valueString.includes( 'x' ) )
|
|
8938
|
+
{
|
|
8939
|
+
this.set( valueString );
|
|
8940
|
+
}
|
|
8941
|
+
} );
|
|
8942
|
+
}
|
|
8943
|
+
|
|
8944
|
+
if( i < ( groups.length - 1 ) )
|
|
8945
|
+
{
|
|
8946
|
+
LX.makeContainer( ["auto", "auto"], "mx-2", `-`, container );
|
|
8947
|
+
}
|
|
8948
|
+
}
|
|
8949
|
+
|
|
8950
|
+
console.assert( itemsCount == valueString.length, "OTP Value/Pattern Mismatch!" )
|
|
8951
|
+
}
|
|
8952
|
+
|
|
8953
|
+
_refreshInput( value );
|
|
8954
|
+
}
|
|
8955
|
+
}
|
|
8956
|
+
|
|
8957
|
+
LX.OTPInput = OTPInput;
|
|
8958
|
+
|
|
8100
8959
|
/**
|
|
8101
8960
|
* @class Pad
|
|
8102
8961
|
* @description Pad Widget
|
|
@@ -8864,7 +9723,7 @@ class Table extends Widget {
|
|
|
8864
9723
|
for( const el of body.childNodes )
|
|
8865
9724
|
{
|
|
8866
9725
|
data.checkMap[ el.getAttribute( "rowId" ) ] = this.checked;
|
|
8867
|
-
el.querySelector( "input" ).checked = this.checked;
|
|
9726
|
+
el.querySelector( "input[type='checkbox']" ).checked = this.checked;
|
|
8868
9727
|
}
|
|
8869
9728
|
});
|
|
8870
9729
|
|
|
@@ -9078,10 +9937,20 @@ class Table extends Widget {
|
|
|
9078
9937
|
input.addEventListener( 'change', function() {
|
|
9079
9938
|
data.checkMap[ rowId ] = this.checked;
|
|
9080
9939
|
|
|
9940
|
+
const headInput = table.querySelector( "thead input[type='checkbox']" );
|
|
9941
|
+
|
|
9081
9942
|
if( !this.checked )
|
|
9082
9943
|
{
|
|
9083
|
-
|
|
9084
|
-
|
|
9944
|
+
headInput.checked = data.checkMap[ ":root" ] = false;
|
|
9945
|
+
}
|
|
9946
|
+
else
|
|
9947
|
+
{
|
|
9948
|
+
const rowInputs = Array.from( table.querySelectorAll( "tbody input[type='checkbox']" ) );
|
|
9949
|
+
const uncheckedRowInputs = rowInputs.filter( i => { return !i.checked; } );
|
|
9950
|
+
if( !uncheckedRowInputs.length )
|
|
9951
|
+
{
|
|
9952
|
+
headInput.checked = data.checkMap[ ":root" ] = true;
|
|
9953
|
+
}
|
|
9085
9954
|
}
|
|
9086
9955
|
});
|
|
9087
9956
|
|
|
@@ -10192,6 +11061,22 @@ class Panel {
|
|
|
10192
11061
|
return this._attachWidget( widget );
|
|
10193
11062
|
}
|
|
10194
11063
|
|
|
11064
|
+
/**
|
|
11065
|
+
* @method addOTP
|
|
11066
|
+
* @param {String} name Widget name
|
|
11067
|
+
* @param {String} value Default numeric value in string format
|
|
11068
|
+
* @param {Function} callback Callback function on change
|
|
11069
|
+
* @param {Object} options:
|
|
11070
|
+
* hideName: Don't use name as label [false]
|
|
11071
|
+
* disabled: Make the widget disabled [false]
|
|
11072
|
+
* pattern: OTP numeric pattern
|
|
11073
|
+
*/
|
|
11074
|
+
|
|
11075
|
+
addOTP( name, value, callback, options = {} ) {
|
|
11076
|
+
const widget = new OTPInput( name, value, callback, options );
|
|
11077
|
+
return this._attachWidget( widget );
|
|
11078
|
+
}
|
|
11079
|
+
|
|
10195
11080
|
/**
|
|
10196
11081
|
* @method addPad
|
|
10197
11082
|
* @param {String} name Widget name
|
|
@@ -10424,7 +11309,7 @@ class Branch {
|
|
|
10424
11309
|
// add widgets
|
|
10425
11310
|
for( let w of this.widgets )
|
|
10426
11311
|
{
|
|
10427
|
-
p.root.appendChild( w.
|
|
11312
|
+
p.root.appendChild( w.root );
|
|
10428
11313
|
}
|
|
10429
11314
|
});
|
|
10430
11315
|
dialog.widgets = this.widgets;
|
|
@@ -10728,7 +11613,7 @@ class Dialog {
|
|
|
10728
11613
|
|
|
10729
11614
|
for( let w of that.widgets )
|
|
10730
11615
|
{
|
|
10731
|
-
branch.content.appendChild( w.
|
|
11616
|
+
branch.content.appendChild( w.root );
|
|
10732
11617
|
}
|
|
10733
11618
|
|
|
10734
11619
|
branch.widgets = that.widgets;
|
|
@@ -12369,7 +13254,7 @@ class AssetView {
|
|
|
12369
13254
|
|
|
12370
13255
|
this.rightPanel.addText(null, this.path.join('/'), null, {
|
|
12371
13256
|
inputClass: "nobg", disabled: true, signal: "@on_folder_change",
|
|
12372
|
-
style: { fontWeight: "600", fontSize: "15px" }
|
|
13257
|
+
style: { fontWeight: "600", fontSize: "15px" }
|
|
12373
13258
|
});
|
|
12374
13259
|
|
|
12375
13260
|
this.rightPanel.endLine();
|
|
@@ -13106,7 +13991,7 @@ Element.prototype.addClass = function( className ) {
|
|
|
13106
13991
|
}
|
|
13107
13992
|
|
|
13108
13993
|
Element.prototype.getComputedSize = function() {
|
|
13109
|
-
// Since we use "box-sizing: border-box" now,
|
|
13994
|
+
// Since we use "box-sizing: border-box" now,
|
|
13110
13995
|
// it's all included in offsetWidth/offsetHeight
|
|
13111
13996
|
return {
|
|
13112
13997
|
width: this.offsetWidth,
|
|
@@ -13248,6 +14133,7 @@ LX.ICONS = {
|
|
|
13248
14133
|
"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"],
|
|
13249
14134
|
"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"],
|
|
13250
14135
|
"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"],
|
|
14136
|
+
"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"],
|
|
13251
14137
|
"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"],
|
|
13252
14138
|
"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"],
|
|
13253
14139
|
"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"],
|