lexgui 0.6.4 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/codeeditor.js +10 -10
- package/build/components/nodegraph.js +12 -12
- package/build/components/timeline.js +170 -175
- package/build/lexgui.js +1219 -1130
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +1235 -1146
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +13 -1
- package/demo.js +1 -1
- package/examples/all_widgets.html +1 -1
- package/examples/editor.html +1 -1
- package/package.json +1 -1
package/build/lexgui.module.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// This is a generated file. Do not edit.
|
|
1
|
+
// This is a generated file. Do not edit.
|
|
2
2
|
// Lexgui.js @jxarco
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const LX = {
|
|
10
|
-
version: "0.6.
|
|
10
|
+
version: "0.6.5",
|
|
11
11
|
ready: false,
|
|
12
12
|
components: [], // Specific pre-build components
|
|
13
13
|
signals: {}, // Events and triggers
|
|
@@ -590,549 +590,408 @@ function setCommandbarState( value, resetEntries = true )
|
|
|
590
590
|
|
|
591
591
|
LX.setCommandbarState = setCommandbarState;
|
|
592
592
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
* @param {String} title (Optional)
|
|
597
|
-
* @param {Object} options
|
|
598
|
-
* id: Id of the message dialog
|
|
599
|
-
* position: Dialog position in screen [screen centered]
|
|
600
|
-
* draggable: Dialog can be dragged [false]
|
|
601
|
-
*/
|
|
602
|
-
|
|
603
|
-
function message( text, title, options = {} )
|
|
604
|
-
{
|
|
605
|
-
if( !text )
|
|
606
|
-
{
|
|
607
|
-
throw( "No message to show" );
|
|
608
|
-
}
|
|
593
|
+
/*
|
|
594
|
+
* Events and Signals
|
|
595
|
+
*/
|
|
609
596
|
|
|
610
|
-
|
|
597
|
+
class IEvent {
|
|
611
598
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
599
|
+
constructor( name, value, domEvent ) {
|
|
600
|
+
this.name = name;
|
|
601
|
+
this.value = value;
|
|
602
|
+
this.domEvent = domEvent;
|
|
603
|
+
}
|
|
615
604
|
}
|
|
605
|
+
LX.IEvent = IEvent;
|
|
616
606
|
|
|
617
|
-
|
|
607
|
+
class TreeEvent {
|
|
618
608
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
*/
|
|
609
|
+
static NONE = 0;
|
|
610
|
+
static NODE_SELECTED = 1;
|
|
611
|
+
static NODE_DELETED = 2;
|
|
612
|
+
static NODE_DBLCLICKED = 3;
|
|
613
|
+
static NODE_CONTEXTMENU = 4;
|
|
614
|
+
static NODE_DRAGGED = 5;
|
|
615
|
+
static NODE_RENAMED = 6;
|
|
616
|
+
static NODE_VISIBILITY = 7;
|
|
617
|
+
static NODE_CARETCHANGED = 8;
|
|
629
618
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
619
|
+
constructor( type, node, value ) {
|
|
620
|
+
this.type = type || TreeEvent.NONE;
|
|
621
|
+
this.node = node;
|
|
622
|
+
this.value = value;
|
|
623
|
+
this.multiple = false; // Multiple selection
|
|
624
|
+
this.panel = null;
|
|
635
625
|
}
|
|
636
626
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
627
|
+
string() {
|
|
628
|
+
switch( this.type )
|
|
629
|
+
{
|
|
630
|
+
case TreeEvent.NONE: return "tree_event_none";
|
|
631
|
+
case TreeEvent.NODE_SELECTED: return "tree_event_selected";
|
|
632
|
+
case TreeEvent.NODE_DELETED: return "tree_event_deleted";
|
|
633
|
+
case TreeEvent.NODE_DBLCLICKED: return "tree_event_dblclick";
|
|
634
|
+
case TreeEvent.NODE_CONTEXTMENU: return "tree_event_contextmenu";
|
|
635
|
+
case TreeEvent.NODE_DRAGGED: return "tree_event_dragged";
|
|
636
|
+
case TreeEvent.NODE_RENAMED: return "tree_event_renamed";
|
|
637
|
+
case TreeEvent.NODE_VISIBILITY: return "tree_event_visibility";
|
|
638
|
+
case TreeEvent.NODE_CARETCHANGED: return "tree_event_caretchanged";
|
|
639
|
+
}
|
|
640
|
+
}
|
|
650
641
|
}
|
|
642
|
+
LX.TreeEvent = TreeEvent;
|
|
651
643
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
/**
|
|
655
|
-
* @method prompt
|
|
656
|
-
* @param {String} text
|
|
657
|
-
* @param {String} title (Optional)
|
|
658
|
-
* @param {Object} options
|
|
659
|
-
* id: Id of the prompt dialog
|
|
660
|
-
* position: Dialog position in screen [screen centered]
|
|
661
|
-
* draggable: Dialog can be dragged [false]
|
|
662
|
-
* input: If false, no text input appears
|
|
663
|
-
* accept: Accept text
|
|
664
|
-
* required: Input has to be filled [true]. Default: false
|
|
665
|
-
*/
|
|
666
|
-
|
|
667
|
-
function prompt( text, title, callback, options = {} )
|
|
644
|
+
function emit( signalName, value, options = {} )
|
|
668
645
|
{
|
|
669
|
-
|
|
670
|
-
options.className = "prompt";
|
|
671
|
-
|
|
672
|
-
let value = "";
|
|
646
|
+
const data = LX.signals[ signalName ];
|
|
673
647
|
|
|
674
|
-
|
|
648
|
+
if( !data )
|
|
649
|
+
{
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
675
652
|
|
|
676
|
-
|
|
653
|
+
const target = options.target;
|
|
677
654
|
|
|
678
|
-
|
|
655
|
+
if( target )
|
|
656
|
+
{
|
|
657
|
+
if( target[ signalName ])
|
|
679
658
|
{
|
|
680
|
-
|
|
659
|
+
target[ signalName ].call( target, value );
|
|
681
660
|
}
|
|
682
661
|
|
|
683
|
-
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
684
664
|
|
|
685
|
-
|
|
665
|
+
for( let obj of data )
|
|
666
|
+
{
|
|
667
|
+
if( obj instanceof LX.Widget )
|
|
668
|
+
{
|
|
669
|
+
obj.set( value, options.skipCallback ?? true );
|
|
670
|
+
}
|
|
671
|
+
else if( obj.constructor === Function )
|
|
672
|
+
{
|
|
673
|
+
const fn = obj;
|
|
674
|
+
fn( null, value );
|
|
675
|
+
}
|
|
676
|
+
else
|
|
677
|
+
{
|
|
678
|
+
// This is an element
|
|
679
|
+
const fn = obj[ signalName ];
|
|
680
|
+
console.assert( fn, `No callback registered with _${ signalName }_ signal` );
|
|
681
|
+
fn.bind( obj )( value );
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
686
685
|
|
|
687
|
-
|
|
688
|
-
if( options.required && value === '' )
|
|
689
|
-
{
|
|
690
|
-
text += text.includes("You must fill the input text.") ? "": "\nYou must fill the input text.";
|
|
691
|
-
dialog.close();
|
|
692
|
-
prompt( text, title, callback, options );
|
|
693
|
-
}
|
|
694
|
-
else
|
|
695
|
-
{
|
|
696
|
-
if( callback ) callback.call( this, value );
|
|
697
|
-
dialog.close();
|
|
698
|
-
}
|
|
699
|
-
}, { buttonClass: "primary" });
|
|
686
|
+
LX.emit = emit;
|
|
700
687
|
|
|
701
|
-
|
|
688
|
+
function addSignal( name, obj, callback )
|
|
689
|
+
{
|
|
690
|
+
obj[ name ] = callback;
|
|
702
691
|
|
|
703
|
-
|
|
704
|
-
if( options.input ?? true )
|
|
692
|
+
if( !LX.signals[ name ] )
|
|
705
693
|
{
|
|
706
|
-
|
|
694
|
+
LX.signals[ name ] = [];
|
|
707
695
|
}
|
|
708
696
|
|
|
709
|
-
|
|
697
|
+
if( LX.signals[ name ].indexOf( obj ) > -1 )
|
|
698
|
+
{
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
LX.signals[ name ].push( obj );
|
|
710
703
|
}
|
|
711
704
|
|
|
712
|
-
LX.
|
|
705
|
+
LX.addSignal = addSignal;
|
|
706
|
+
|
|
707
|
+
/*
|
|
708
|
+
* DOM Elements
|
|
709
|
+
*/
|
|
713
710
|
|
|
714
711
|
/**
|
|
715
|
-
* @
|
|
716
|
-
* @param {String} title
|
|
717
|
-
* @param {String} description (Optional)
|
|
718
|
-
* @param {Object} options
|
|
719
|
-
* action: Data of the custom action { name, callback }
|
|
720
|
-
* closable: Allow closing the toast
|
|
721
|
-
* timeout: Time in which the toast closed automatically, in ms. -1 means persistent. [3000]
|
|
712
|
+
* @class Popover
|
|
722
713
|
*/
|
|
723
714
|
|
|
724
|
-
|
|
725
|
-
{
|
|
726
|
-
if( !title )
|
|
727
|
-
{
|
|
728
|
-
throw( "The toast needs at least a title!" );
|
|
729
|
-
}
|
|
715
|
+
class Popover {
|
|
730
716
|
|
|
731
|
-
|
|
717
|
+
static activeElement = false;
|
|
732
718
|
|
|
733
|
-
|
|
734
|
-
toast.className = "lextoast";
|
|
735
|
-
toast.style.translate = "0 calc(100% + 30px)";
|
|
736
|
-
this.notifications.prepend( toast );
|
|
719
|
+
constructor( trigger, content, options = {} ) {
|
|
737
720
|
|
|
738
|
-
|
|
721
|
+
console.assert( trigger, "Popover needs a DOM element as trigger!" );
|
|
739
722
|
|
|
740
|
-
if(
|
|
723
|
+
if( Popover.activeElement )
|
|
741
724
|
{
|
|
742
|
-
|
|
743
|
-
|
|
725
|
+
Popover.activeElement.destroy();
|
|
726
|
+
return;
|
|
744
727
|
}
|
|
745
728
|
|
|
746
|
-
|
|
747
|
-
|
|
729
|
+
this._trigger = trigger;
|
|
730
|
+
trigger.classList.add( "triggered" );
|
|
731
|
+
trigger.active = this;
|
|
748
732
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
733
|
+
this._windowPadding = 4;
|
|
734
|
+
this.side = options.side ?? "bottom";
|
|
735
|
+
this.align = options.align ?? "center";
|
|
736
|
+
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
752
737
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
738
|
+
this.root = document.createElement( "div" );
|
|
739
|
+
this.root.dataset["side"] = this.side;
|
|
740
|
+
this.root.tabIndex = "1";
|
|
741
|
+
this.root.className = "lexpopover";
|
|
742
|
+
LX.root.appendChild( this.root );
|
|
757
743
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
744
|
+
this.root.addEventListener( "keydown", (e) => {
|
|
745
|
+
if( e.key == "Escape" )
|
|
746
|
+
{
|
|
747
|
+
e.preventDefault();
|
|
748
|
+
e.stopPropagation();
|
|
749
|
+
this.destroy();
|
|
750
|
+
}
|
|
751
|
+
} );
|
|
765
752
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
753
|
+
if( content )
|
|
754
|
+
{
|
|
755
|
+
content = [].concat( content );
|
|
756
|
+
content.forEach( e => {
|
|
757
|
+
const domNode = e.root ?? e;
|
|
758
|
+
this.root.appendChild( domNode );
|
|
759
|
+
if( e.onPopover )
|
|
760
|
+
{
|
|
761
|
+
e.onPopover();
|
|
762
|
+
}
|
|
763
|
+
} );
|
|
764
|
+
}
|
|
772
765
|
|
|
773
|
-
|
|
766
|
+
Popover.activeElement = this;
|
|
774
767
|
|
|
775
|
-
toast.close = function() {
|
|
776
|
-
this.dataset[ "closed" ] = true;
|
|
777
768
|
LX.doAsync( () => {
|
|
778
|
-
this.
|
|
779
|
-
if( !that.notifications.childElementCount )
|
|
780
|
-
{
|
|
781
|
-
that.notifications.style.width = "unset";
|
|
782
|
-
that.notifications.iWidth = 0;
|
|
783
|
-
}
|
|
784
|
-
}, 500 );
|
|
785
|
-
};
|
|
769
|
+
this._adjustPosition();
|
|
786
770
|
|
|
787
|
-
|
|
788
|
-
{
|
|
789
|
-
const closeIcon = LX.makeIcon( "X", { iconClass: "closer" } );
|
|
790
|
-
closeIcon.addEventListener( "click", () => {
|
|
791
|
-
toast.close();
|
|
792
|
-
} );
|
|
793
|
-
toast.appendChild( closeIcon );
|
|
794
|
-
}
|
|
771
|
+
this.root.focus();
|
|
795
772
|
|
|
796
|
-
|
|
773
|
+
this._onClick = e => {
|
|
774
|
+
if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
|
|
775
|
+
{
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
this.destroy();
|
|
779
|
+
};
|
|
797
780
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
toast.close();
|
|
802
|
-
}, timeout );
|
|
781
|
+
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
782
|
+
document.body.addEventListener( "focusin", this._onClick, true );
|
|
783
|
+
}, 10 );
|
|
803
784
|
}
|
|
804
|
-
}
|
|
805
785
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
/**
|
|
809
|
-
* @method badge
|
|
810
|
-
* @param {String} text
|
|
811
|
-
* @param {String} className
|
|
812
|
-
* @param {Object} options
|
|
813
|
-
* style: Style attributes to override
|
|
814
|
-
* asElement: Returns the badge as HTMLElement [false]
|
|
815
|
-
*/
|
|
786
|
+
destroy() {
|
|
816
787
|
|
|
817
|
-
|
|
818
|
-
{
|
|
819
|
-
const container = document.createElement( "div" );
|
|
820
|
-
container.innerHTML = text;
|
|
821
|
-
container.className = "lexbadge " + ( className ?? "" );
|
|
822
|
-
Object.assign( container.style, options.style ?? {} );
|
|
823
|
-
return ( options.asElement ?? false ) ? container : container.outerHTML;
|
|
824
|
-
}
|
|
788
|
+
this._trigger.classList.remove( "triggered" );
|
|
825
789
|
|
|
826
|
-
|
|
790
|
+
delete this._trigger.active;
|
|
827
791
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
* @param {String} htmlType
|
|
831
|
-
* @param {String} className
|
|
832
|
-
* @param {String} innerHTML
|
|
833
|
-
* @param {HTMLElement} parent
|
|
834
|
-
* @param {Object} overrideStyle
|
|
835
|
-
*/
|
|
792
|
+
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
793
|
+
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
836
794
|
|
|
837
|
-
|
|
838
|
-
{
|
|
839
|
-
const element = document.createElement( htmlType );
|
|
840
|
-
element.className = className ?? "";
|
|
841
|
-
element.innerHTML = innerHTML ?? "";
|
|
842
|
-
Object.assign( element.style, overrideStyle );
|
|
795
|
+
this.root.remove();
|
|
843
796
|
|
|
844
|
-
|
|
845
|
-
{
|
|
846
|
-
if( parent.attach ) // Use attach method if possible
|
|
847
|
-
{
|
|
848
|
-
parent.attach( element );
|
|
849
|
-
}
|
|
850
|
-
else // its a native HTMLElement
|
|
851
|
-
{
|
|
852
|
-
parent.appendChild( element );
|
|
853
|
-
}
|
|
797
|
+
Popover.activeElement = null;
|
|
854
798
|
}
|
|
855
799
|
|
|
856
|
-
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
LX.makeElement = makeElement;
|
|
860
|
-
|
|
861
|
-
/**
|
|
862
|
-
* @method makeContainer
|
|
863
|
-
* @param {Array} size
|
|
864
|
-
* @param {String} className
|
|
865
|
-
* @param {String} innerHTML
|
|
866
|
-
* @param {HTMLElement} parent
|
|
867
|
-
* @param {Object} overrideStyle
|
|
868
|
-
*/
|
|
869
|
-
|
|
870
|
-
function makeContainer( size, className, innerHTML, parent, overrideStyle = {} )
|
|
871
|
-
{
|
|
872
|
-
const container = LX.makeElement( "div", "lexcontainer " + ( className ?? "" ), innerHTML, parent, overrideStyle );
|
|
873
|
-
container.style.width = size && size[ 0 ] ? size[ 0 ] : "100%";
|
|
874
|
-
container.style.height = size && size[ 1 ] ? size[ 1 ] : "100%";
|
|
875
|
-
return container;
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
LX.makeContainer = makeContainer;
|
|
879
|
-
|
|
880
|
-
/**
|
|
881
|
-
* @method asTooltip
|
|
882
|
-
* @param {HTMLElement} trigger
|
|
883
|
-
* @param {String} content
|
|
884
|
-
* @param {Object} options
|
|
885
|
-
* side: Side of the tooltip
|
|
886
|
-
* offset: Tooltip margin offset
|
|
887
|
-
* active: Tooltip active by default [true]
|
|
888
|
-
*/
|
|
889
|
-
|
|
890
|
-
function asTooltip( trigger, content, options = {} )
|
|
891
|
-
{
|
|
892
|
-
console.assert( trigger, "You need a trigger to generate a tooltip!" );
|
|
893
|
-
|
|
894
|
-
trigger.dataset[ "disableTooltip" ] = !( options.active ?? true );
|
|
895
|
-
|
|
896
|
-
let tooltipDom = null;
|
|
800
|
+
_adjustPosition() {
|
|
897
801
|
|
|
898
|
-
|
|
802
|
+
const position = [ 0, 0 ];
|
|
899
803
|
|
|
900
|
-
|
|
804
|
+
// Place menu using trigger position and user options
|
|
901
805
|
{
|
|
902
|
-
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
LX.root.querySelectorAll( ".lextooltip" ).forEach( e => e.remove() );
|
|
906
|
-
|
|
907
|
-
tooltipDom = document.createElement( "div" );
|
|
908
|
-
tooltipDom.className = "lextooltip";
|
|
909
|
-
tooltipDom.innerHTML = content;
|
|
910
|
-
|
|
911
|
-
LX.doAsync( () => {
|
|
806
|
+
const rect = this._trigger.getBoundingClientRect();
|
|
912
807
|
|
|
913
|
-
const position = [ 0, 0 ];
|
|
914
|
-
const rect = this.getBoundingClientRect();
|
|
915
|
-
const offset = options.offset ?? 6;
|
|
916
808
|
let alignWidth = true;
|
|
917
809
|
|
|
918
|
-
switch(
|
|
810
|
+
switch( this.side )
|
|
919
811
|
{
|
|
920
812
|
case "left":
|
|
921
|
-
position[ 0 ] += ( rect.x -
|
|
813
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
922
814
|
alignWidth = false;
|
|
923
815
|
break;
|
|
924
816
|
case "right":
|
|
925
|
-
position[ 0 ] += ( rect.x + rect.width
|
|
817
|
+
position[ 0 ] += ( rect.x + rect.width );
|
|
926
818
|
alignWidth = false;
|
|
927
819
|
break;
|
|
928
820
|
case "top":
|
|
929
|
-
position[ 1 ] += ( rect.y -
|
|
821
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
930
822
|
alignWidth = true;
|
|
931
823
|
break;
|
|
932
824
|
case "bottom":
|
|
933
|
-
position[ 1 ] += ( rect.y + rect.height
|
|
825
|
+
position[ 1 ] += ( rect.y + rect.height );
|
|
934
826
|
alignWidth = true;
|
|
935
827
|
break;
|
|
936
828
|
}
|
|
937
829
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
830
|
+
switch( this.align )
|
|
831
|
+
{
|
|
832
|
+
case "start":
|
|
833
|
+
if( alignWidth ) { position[ 0 ] += rect.x; }
|
|
834
|
+
else { position[ 1 ] += rect.y; }
|
|
835
|
+
break;
|
|
836
|
+
case "center":
|
|
837
|
+
if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - this.root.offsetWidth * 0.5; }
|
|
838
|
+
else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - this.root.offsetHeight * 0.5; }
|
|
839
|
+
break;
|
|
840
|
+
case "end":
|
|
841
|
+
if( alignWidth ) { position[ 0 ] += rect.x - this.root.offsetWidth + rect.width; }
|
|
842
|
+
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
951
846
|
|
|
952
|
-
|
|
953
|
-
if( tooltipDom )
|
|
847
|
+
if( this.avoidCollisions )
|
|
954
848
|
{
|
|
955
|
-
|
|
849
|
+
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - this.root.offsetWidth - this._windowPadding );
|
|
850
|
+
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - this.root.offsetHeight - this._windowPadding );
|
|
956
851
|
}
|
|
957
|
-
|
|
852
|
+
|
|
853
|
+
this.root.style.left = `${ position[ 0 ] }px`;
|
|
854
|
+
this.root.style.top = `${ position[ 1 ] }px`;
|
|
855
|
+
}
|
|
958
856
|
}
|
|
857
|
+
LX.Popover = Popover;
|
|
959
858
|
|
|
960
|
-
|
|
859
|
+
/**
|
|
860
|
+
* @class Sheet
|
|
861
|
+
*/
|
|
961
862
|
|
|
962
|
-
|
|
963
|
-
* Events and Signals
|
|
964
|
-
*/
|
|
863
|
+
class Sheet {
|
|
965
864
|
|
|
966
|
-
|
|
865
|
+
constructor( size, content, options = {} ) {
|
|
967
866
|
|
|
968
|
-
|
|
969
|
-
this.name = name;
|
|
970
|
-
this.value = value;
|
|
971
|
-
this.domEvent = domEvent;
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
LX.IEvent = IEvent;
|
|
867
|
+
this.side = options.side ?? "left";
|
|
975
868
|
|
|
976
|
-
|
|
869
|
+
this.root = document.createElement( "div" );
|
|
870
|
+
this.root.dataset["side"] = this.side;
|
|
871
|
+
this.root.tabIndex = "1";
|
|
872
|
+
this.root.role = "dialog";
|
|
873
|
+
this.root.className = "lexsheet fixed z-100 bg-primary";
|
|
874
|
+
LX.root.appendChild( this.root );
|
|
977
875
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
static NODE_CARETCHANGED = 8;
|
|
876
|
+
this.root.addEventListener( "keydown", (e) => {
|
|
877
|
+
if( e.key == "Escape" )
|
|
878
|
+
{
|
|
879
|
+
e.preventDefault();
|
|
880
|
+
e.stopPropagation();
|
|
881
|
+
this.destroy();
|
|
882
|
+
}
|
|
883
|
+
} );
|
|
987
884
|
|
|
988
|
-
|
|
989
|
-
this.type = type || TreeEvent.NONE;
|
|
990
|
-
this.node = node;
|
|
991
|
-
this.value = value;
|
|
992
|
-
this.multiple = false; // Multiple selection
|
|
993
|
-
this.panel = null;
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
string() {
|
|
997
|
-
switch( this.type )
|
|
885
|
+
if( content )
|
|
998
886
|
{
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
887
|
+
content = [].concat( content );
|
|
888
|
+
content.forEach( e => {
|
|
889
|
+
const domNode = e.root ?? e;
|
|
890
|
+
this.root.appendChild( domNode );
|
|
891
|
+
if( e.onSheet )
|
|
892
|
+
{
|
|
893
|
+
e.onSheet();
|
|
894
|
+
}
|
|
895
|
+
} );
|
|
1008
896
|
}
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
LX.TreeEvent = TreeEvent;
|
|
1012
897
|
|
|
1013
|
-
|
|
1014
|
-
{
|
|
1015
|
-
const data = LX.signals[ signalName ];
|
|
898
|
+
LX.doAsync( () => {
|
|
1016
899
|
|
|
1017
|
-
|
|
1018
|
-
{
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
900
|
+
LX.modal.toggle( false );
|
|
1021
901
|
|
|
1022
|
-
|
|
902
|
+
switch( this.side )
|
|
903
|
+
{
|
|
904
|
+
case "left":
|
|
905
|
+
this.root.style.left = 0;
|
|
906
|
+
this.root.style.width = size;
|
|
907
|
+
this.root.style.height = "100%";
|
|
908
|
+
break;
|
|
909
|
+
case "right":
|
|
910
|
+
this.root.style.right = 0;
|
|
911
|
+
this.root.style.width = size;
|
|
912
|
+
this.root.style.height = "100%";
|
|
913
|
+
break;
|
|
914
|
+
case "top":
|
|
915
|
+
this.root.style.top = 0;
|
|
916
|
+
this.root.style.width = "100%";
|
|
917
|
+
this.root.style.height = size;
|
|
918
|
+
break;
|
|
919
|
+
case "bottom":
|
|
920
|
+
this.root.style.bottom = 0;
|
|
921
|
+
this.root.style.width = "100%";
|
|
922
|
+
this.root.style.height = size;
|
|
923
|
+
break;
|
|
924
|
+
}
|
|
1023
925
|
|
|
1024
|
-
|
|
1025
|
-
{
|
|
1026
|
-
if( target[ signalName ])
|
|
1027
|
-
{
|
|
1028
|
-
target[ signalName ].call( target, value );
|
|
1029
|
-
}
|
|
926
|
+
this.root.focus();
|
|
1030
927
|
|
|
1031
|
-
|
|
1032
|
-
|
|
928
|
+
this._onClick = e => {
|
|
929
|
+
if( e.target && ( this.root.contains( e.target ) ) )
|
|
930
|
+
{
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
this.destroy();
|
|
934
|
+
};
|
|
1033
935
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
{
|
|
1038
|
-
obj.set( value, options.skipCallback ?? true );
|
|
1039
|
-
}
|
|
1040
|
-
else if( obj.constructor === Function )
|
|
1041
|
-
{
|
|
1042
|
-
const fn = obj;
|
|
1043
|
-
fn( null, value );
|
|
1044
|
-
}
|
|
1045
|
-
else
|
|
1046
|
-
{
|
|
1047
|
-
// This is an element
|
|
1048
|
-
const fn = obj[ signalName ];
|
|
1049
|
-
console.assert( fn, `No callback registered with _${ signalName }_ signal` );
|
|
1050
|
-
fn.bind( obj )( value );
|
|
1051
|
-
}
|
|
936
|
+
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
937
|
+
document.body.addEventListener( "focusin", this._onClick, true );
|
|
938
|
+
}, 10 );
|
|
1052
939
|
}
|
|
1053
|
-
}
|
|
1054
940
|
|
|
1055
|
-
|
|
941
|
+
destroy() {
|
|
1056
942
|
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
obj[ name ] = callback;
|
|
943
|
+
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
944
|
+
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
1060
945
|
|
|
1061
|
-
|
|
1062
|
-
{
|
|
1063
|
-
LX.signals[ name ] = [];
|
|
1064
|
-
}
|
|
946
|
+
this.root.remove();
|
|
1065
947
|
|
|
1066
|
-
|
|
1067
|
-
{
|
|
1068
|
-
return;
|
|
948
|
+
LX.modal.toggle( true );
|
|
1069
949
|
}
|
|
1070
|
-
|
|
1071
|
-
LX.signals[ name ].push( obj );
|
|
1072
950
|
}
|
|
1073
|
-
|
|
1074
|
-
LX.addSignal = addSignal;
|
|
1075
|
-
|
|
1076
|
-
/*
|
|
1077
|
-
* DOM Elements
|
|
1078
|
-
*/
|
|
951
|
+
LX.Sheet = Sheet;
|
|
1079
952
|
|
|
1080
953
|
/**
|
|
1081
|
-
* @class
|
|
954
|
+
* @class DropdownMenu
|
|
1082
955
|
*/
|
|
1083
956
|
|
|
1084
|
-
class
|
|
957
|
+
class DropdownMenu {
|
|
1085
958
|
|
|
1086
|
-
static
|
|
959
|
+
static currentMenu = false;
|
|
1087
960
|
|
|
1088
|
-
constructor( trigger,
|
|
961
|
+
constructor( trigger, items, options = {} ) {
|
|
1089
962
|
|
|
1090
|
-
console.assert( trigger, "
|
|
963
|
+
console.assert( trigger, "DropdownMenu needs a DOM element as trigger!" );
|
|
1091
964
|
|
|
1092
|
-
if(
|
|
965
|
+
if( DropdownMenu.currentMenu || !items?.length )
|
|
1093
966
|
{
|
|
1094
|
-
|
|
967
|
+
DropdownMenu.currentMenu.destroy();
|
|
968
|
+
this.invalid = true;
|
|
1095
969
|
return;
|
|
1096
970
|
}
|
|
1097
971
|
|
|
1098
972
|
this._trigger = trigger;
|
|
1099
973
|
trigger.classList.add( "triggered" );
|
|
1100
|
-
trigger.
|
|
974
|
+
trigger.ddm = this;
|
|
975
|
+
|
|
976
|
+
this._items = items;
|
|
1101
977
|
|
|
1102
978
|
this._windowPadding = 4;
|
|
1103
979
|
this.side = options.side ?? "bottom";
|
|
1104
980
|
this.align = options.align ?? "center";
|
|
1105
981
|
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
982
|
+
this.onBlur = options.onBlur;
|
|
983
|
+
this.inPlace = false;
|
|
1106
984
|
|
|
1107
985
|
this.root = document.createElement( "div" );
|
|
986
|
+
this.root.id = "root";
|
|
1108
987
|
this.root.dataset["side"] = this.side;
|
|
1109
988
|
this.root.tabIndex = "1";
|
|
1110
|
-
this.root.className = "
|
|
989
|
+
this.root.className = "lexdropdownmenu";
|
|
1111
990
|
LX.root.appendChild( this.root );
|
|
1112
991
|
|
|
1113
|
-
this.
|
|
1114
|
-
if( e.key == "Escape" )
|
|
1115
|
-
{
|
|
1116
|
-
e.preventDefault();
|
|
1117
|
-
e.stopPropagation();
|
|
1118
|
-
this.destroy();
|
|
1119
|
-
}
|
|
1120
|
-
} );
|
|
1121
|
-
|
|
1122
|
-
if( content )
|
|
1123
|
-
{
|
|
1124
|
-
content = [].concat( content );
|
|
1125
|
-
content.forEach( e => {
|
|
1126
|
-
const domNode = e.root ?? e;
|
|
1127
|
-
this.root.appendChild( domNode );
|
|
1128
|
-
if( e.onPopover )
|
|
1129
|
-
{
|
|
1130
|
-
e.onPopover();
|
|
1131
|
-
}
|
|
1132
|
-
} );
|
|
1133
|
-
}
|
|
992
|
+
this._create( this._items );
|
|
1134
993
|
|
|
1135
|
-
|
|
994
|
+
DropdownMenu.currentMenu = this;
|
|
1136
995
|
|
|
1137
996
|
LX.doAsync( () => {
|
|
1138
997
|
this._adjustPosition();
|
|
@@ -1140,11 +999,14 @@ class Popover {
|
|
|
1140
999
|
this.root.focus();
|
|
1141
1000
|
|
|
1142
1001
|
this._onClick = e => {
|
|
1143
|
-
|
|
1002
|
+
|
|
1003
|
+
// Check if the click is inside a menu or on the trigger
|
|
1004
|
+
if( e.target && ( e.target.closest( ".lexdropdownmenu" ) != undefined || e.target == this._trigger ) )
|
|
1144
1005
|
{
|
|
1145
1006
|
return;
|
|
1146
1007
|
}
|
|
1147
|
-
|
|
1008
|
+
|
|
1009
|
+
this.destroy( true );
|
|
1148
1010
|
};
|
|
1149
1011
|
|
|
1150
1012
|
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
@@ -1152,298 +1014,67 @@ class Popover {
|
|
|
1152
1014
|
}, 10 );
|
|
1153
1015
|
}
|
|
1154
1016
|
|
|
1155
|
-
destroy() {
|
|
1017
|
+
destroy( blurEvent ) {
|
|
1156
1018
|
|
|
1157
1019
|
this._trigger.classList.remove( "triggered" );
|
|
1158
1020
|
|
|
1159
|
-
delete this._trigger.
|
|
1021
|
+
delete this._trigger.ddm;
|
|
1160
1022
|
|
|
1161
1023
|
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
1162
1024
|
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
1163
1025
|
|
|
1164
|
-
|
|
1026
|
+
LX.root.querySelectorAll( ".lexdropdownmenu" ).forEach( m => { m.remove(); } );
|
|
1165
1027
|
|
|
1166
|
-
|
|
1167
|
-
}
|
|
1028
|
+
DropdownMenu.currentMenu = null;
|
|
1168
1029
|
|
|
1169
|
-
|
|
1030
|
+
if( blurEvent && this.onBlur )
|
|
1031
|
+
{
|
|
1032
|
+
this.onBlur();
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1170
1035
|
|
|
1171
|
-
|
|
1036
|
+
_create( items, parentDom ) {
|
|
1172
1037
|
|
|
1173
|
-
|
|
1038
|
+
if( !parentDom )
|
|
1174
1039
|
{
|
|
1175
|
-
|
|
1040
|
+
parentDom = this.root;
|
|
1041
|
+
}
|
|
1042
|
+
else
|
|
1043
|
+
{
|
|
1044
|
+
const parentRect = parentDom.getBoundingClientRect();
|
|
1176
1045
|
|
|
1177
|
-
let
|
|
1046
|
+
let newParent = document.createElement( "div" );
|
|
1047
|
+
newParent.tabIndex = "1";
|
|
1048
|
+
newParent.className = "lexdropdownmenu";
|
|
1049
|
+
newParent.dataset["id"] = parentDom.dataset["id"];
|
|
1050
|
+
newParent.dataset["side"] = "right"; // submenus always come from the right
|
|
1051
|
+
LX.root.appendChild( newParent );
|
|
1178
1052
|
|
|
1179
|
-
|
|
1053
|
+
newParent.currentParent = parentDom;
|
|
1054
|
+
parentDom = newParent;
|
|
1055
|
+
|
|
1056
|
+
LX.doAsync( () => {
|
|
1057
|
+
const position = [ parentRect.x + parentRect.width, parentRect.y ];
|
|
1058
|
+
|
|
1059
|
+
if( this.avoidCollisions )
|
|
1060
|
+
{
|
|
1061
|
+
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - newParent.offsetWidth - this._windowPadding );
|
|
1062
|
+
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - newParent.offsetHeight - this._windowPadding );
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
newParent.style.left = `${ position[ 0 ] }px`;
|
|
1066
|
+
newParent.style.top = `${ position[ 1 ] }px`;
|
|
1067
|
+
}, 10 );
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
let applyIconPadding = items.filter( i => { return ( i?.icon != undefined ) || ( i?.checked != undefined ) } ).length > 0;
|
|
1071
|
+
|
|
1072
|
+
for( let item of items )
|
|
1073
|
+
{
|
|
1074
|
+
if( !item )
|
|
1180
1075
|
{
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
alignWidth = false;
|
|
1184
|
-
break;
|
|
1185
|
-
case "right":
|
|
1186
|
-
position[ 0 ] += ( rect.x + rect.width );
|
|
1187
|
-
alignWidth = false;
|
|
1188
|
-
break;
|
|
1189
|
-
case "top":
|
|
1190
|
-
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
1191
|
-
alignWidth = true;
|
|
1192
|
-
break;
|
|
1193
|
-
case "bottom":
|
|
1194
|
-
position[ 1 ] += ( rect.y + rect.height );
|
|
1195
|
-
alignWidth = true;
|
|
1196
|
-
break;
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
switch( this.align )
|
|
1200
|
-
{
|
|
1201
|
-
case "start":
|
|
1202
|
-
if( alignWidth ) { position[ 0 ] += rect.x; }
|
|
1203
|
-
else { position[ 1 ] += rect.y; }
|
|
1204
|
-
break;
|
|
1205
|
-
case "center":
|
|
1206
|
-
if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - this.root.offsetWidth * 0.5; }
|
|
1207
|
-
else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - this.root.offsetHeight * 0.5; }
|
|
1208
|
-
break;
|
|
1209
|
-
case "end":
|
|
1210
|
-
if( alignWidth ) { position[ 0 ] += rect.x - this.root.offsetWidth + rect.width; }
|
|
1211
|
-
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
1212
|
-
break;
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
if( this.avoidCollisions )
|
|
1217
|
-
{
|
|
1218
|
-
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - this.root.offsetWidth - this._windowPadding );
|
|
1219
|
-
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - this.root.offsetHeight - this._windowPadding );
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
this.root.style.left = `${ position[ 0 ] }px`;
|
|
1223
|
-
this.root.style.top = `${ position[ 1 ] }px`;
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
LX.Popover = Popover;
|
|
1227
|
-
|
|
1228
|
-
/**
|
|
1229
|
-
* @class Sheet
|
|
1230
|
-
*/
|
|
1231
|
-
|
|
1232
|
-
class Sheet {
|
|
1233
|
-
|
|
1234
|
-
constructor( size, content, options = {} ) {
|
|
1235
|
-
|
|
1236
|
-
this.side = options.side ?? "left";
|
|
1237
|
-
|
|
1238
|
-
this.root = document.createElement( "div" );
|
|
1239
|
-
this.root.dataset["side"] = this.side;
|
|
1240
|
-
this.root.tabIndex = "1";
|
|
1241
|
-
this.root.role = "dialog";
|
|
1242
|
-
this.root.className = "lexsheet fixed z-100 bg-primary";
|
|
1243
|
-
LX.root.appendChild( this.root );
|
|
1244
|
-
|
|
1245
|
-
this.root.addEventListener( "keydown", (e) => {
|
|
1246
|
-
if( e.key == "Escape" )
|
|
1247
|
-
{
|
|
1248
|
-
e.preventDefault();
|
|
1249
|
-
e.stopPropagation();
|
|
1250
|
-
this.destroy();
|
|
1251
|
-
}
|
|
1252
|
-
} );
|
|
1253
|
-
|
|
1254
|
-
if( content )
|
|
1255
|
-
{
|
|
1256
|
-
content = [].concat( content );
|
|
1257
|
-
content.forEach( e => {
|
|
1258
|
-
const domNode = e.root ?? e;
|
|
1259
|
-
this.root.appendChild( domNode );
|
|
1260
|
-
if( e.onSheet )
|
|
1261
|
-
{
|
|
1262
|
-
e.onSheet();
|
|
1263
|
-
}
|
|
1264
|
-
} );
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
LX.doAsync( () => {
|
|
1268
|
-
|
|
1269
|
-
LX.modal.toggle( false );
|
|
1270
|
-
|
|
1271
|
-
switch( this.side )
|
|
1272
|
-
{
|
|
1273
|
-
case "left":
|
|
1274
|
-
this.root.style.left = 0;
|
|
1275
|
-
this.root.style.width = size;
|
|
1276
|
-
this.root.style.height = "100%";
|
|
1277
|
-
break;
|
|
1278
|
-
case "right":
|
|
1279
|
-
this.root.style.right = 0;
|
|
1280
|
-
this.root.style.width = size;
|
|
1281
|
-
this.root.style.height = "100%";
|
|
1282
|
-
break;
|
|
1283
|
-
case "top":
|
|
1284
|
-
this.root.style.top = 0;
|
|
1285
|
-
this.root.style.width = "100%";
|
|
1286
|
-
this.root.style.height = size;
|
|
1287
|
-
break;
|
|
1288
|
-
case "bottom":
|
|
1289
|
-
this.root.style.bottom = 0;
|
|
1290
|
-
this.root.style.width = "100%";
|
|
1291
|
-
this.root.style.height = size;
|
|
1292
|
-
break;
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
this.root.focus();
|
|
1296
|
-
|
|
1297
|
-
this._onClick = e => {
|
|
1298
|
-
if( e.target && ( this.root.contains( e.target ) ) )
|
|
1299
|
-
{
|
|
1300
|
-
return;
|
|
1301
|
-
}
|
|
1302
|
-
this.destroy();
|
|
1303
|
-
};
|
|
1304
|
-
|
|
1305
|
-
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
1306
|
-
document.body.addEventListener( "focusin", this._onClick, true );
|
|
1307
|
-
}, 10 );
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
destroy() {
|
|
1311
|
-
|
|
1312
|
-
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
1313
|
-
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
1314
|
-
|
|
1315
|
-
this.root.remove();
|
|
1316
|
-
|
|
1317
|
-
LX.modal.toggle( true );
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
LX.Sheet = Sheet;
|
|
1321
|
-
|
|
1322
|
-
/**
|
|
1323
|
-
* @class DropdownMenu
|
|
1324
|
-
*/
|
|
1325
|
-
|
|
1326
|
-
class DropdownMenu {
|
|
1327
|
-
|
|
1328
|
-
static currentMenu = false;
|
|
1329
|
-
|
|
1330
|
-
constructor( trigger, items, options = {} ) {
|
|
1331
|
-
|
|
1332
|
-
console.assert( trigger, "DropdownMenu needs a DOM element as trigger!" );
|
|
1333
|
-
|
|
1334
|
-
if( DropdownMenu.currentMenu || !items?.length )
|
|
1335
|
-
{
|
|
1336
|
-
DropdownMenu.currentMenu.destroy();
|
|
1337
|
-
this.invalid = true;
|
|
1338
|
-
return;
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
this._trigger = trigger;
|
|
1342
|
-
trigger.classList.add( "triggered" );
|
|
1343
|
-
trigger.ddm = this;
|
|
1344
|
-
|
|
1345
|
-
this._items = items;
|
|
1346
|
-
|
|
1347
|
-
this._windowPadding = 4;
|
|
1348
|
-
this.side = options.side ?? "bottom";
|
|
1349
|
-
this.align = options.align ?? "center";
|
|
1350
|
-
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
1351
|
-
this.onBlur = options.onBlur;
|
|
1352
|
-
this.inPlace = false;
|
|
1353
|
-
|
|
1354
|
-
this.root = document.createElement( "div" );
|
|
1355
|
-
this.root.id = "root";
|
|
1356
|
-
this.root.dataset["side"] = this.side;
|
|
1357
|
-
this.root.tabIndex = "1";
|
|
1358
|
-
this.root.className = "lexdropdownmenu";
|
|
1359
|
-
LX.root.appendChild( this.root );
|
|
1360
|
-
|
|
1361
|
-
this._create( this._items );
|
|
1362
|
-
|
|
1363
|
-
DropdownMenu.currentMenu = this;
|
|
1364
|
-
|
|
1365
|
-
LX.doAsync( () => {
|
|
1366
|
-
this._adjustPosition();
|
|
1367
|
-
|
|
1368
|
-
this.root.focus();
|
|
1369
|
-
|
|
1370
|
-
this._onClick = e => {
|
|
1371
|
-
|
|
1372
|
-
// Check if the click is inside a menu or on the trigger
|
|
1373
|
-
if( e.target && ( e.target.closest( ".lexdropdownmenu" ) != undefined || e.target == this._trigger ) )
|
|
1374
|
-
{
|
|
1375
|
-
return;
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
|
-
this.destroy( true );
|
|
1379
|
-
};
|
|
1380
|
-
|
|
1381
|
-
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
1382
|
-
document.body.addEventListener( "focusin", this._onClick, true );
|
|
1383
|
-
}, 10 );
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
destroy( blurEvent ) {
|
|
1387
|
-
|
|
1388
|
-
this._trigger.classList.remove( "triggered" );
|
|
1389
|
-
|
|
1390
|
-
delete this._trigger.ddm;
|
|
1391
|
-
|
|
1392
|
-
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
1393
|
-
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
1394
|
-
|
|
1395
|
-
LX.root.querySelectorAll( ".lexdropdownmenu" ).forEach( m => { m.remove(); } );
|
|
1396
|
-
|
|
1397
|
-
DropdownMenu.currentMenu = null;
|
|
1398
|
-
|
|
1399
|
-
if( blurEvent && this.onBlur )
|
|
1400
|
-
{
|
|
1401
|
-
this.onBlur();
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
_create( items, parentDom ) {
|
|
1406
|
-
|
|
1407
|
-
if( !parentDom )
|
|
1408
|
-
{
|
|
1409
|
-
parentDom = this.root;
|
|
1410
|
-
}
|
|
1411
|
-
else
|
|
1412
|
-
{
|
|
1413
|
-
const parentRect = parentDom.getBoundingClientRect();
|
|
1414
|
-
|
|
1415
|
-
let newParent = document.createElement( "div" );
|
|
1416
|
-
newParent.tabIndex = "1";
|
|
1417
|
-
newParent.className = "lexdropdownmenu";
|
|
1418
|
-
newParent.dataset["id"] = parentDom.dataset["id"];
|
|
1419
|
-
newParent.dataset["side"] = "right"; // submenus always come from the right
|
|
1420
|
-
LX.root.appendChild( newParent );
|
|
1421
|
-
|
|
1422
|
-
newParent.currentParent = parentDom;
|
|
1423
|
-
parentDom = newParent;
|
|
1424
|
-
|
|
1425
|
-
LX.doAsync( () => {
|
|
1426
|
-
const position = [ parentRect.x + parentRect.width, parentRect.y ];
|
|
1427
|
-
|
|
1428
|
-
if( this.avoidCollisions )
|
|
1429
|
-
{
|
|
1430
|
-
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - newParent.offsetWidth - this._windowPadding );
|
|
1431
|
-
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - newParent.offsetHeight - this._windowPadding );
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
newParent.style.left = `${ position[ 0 ] }px`;
|
|
1435
|
-
newParent.style.top = `${ position[ 1 ] }px`;
|
|
1436
|
-
}, 10 );
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
let applyIconPadding = items.filter( i => { return ( i?.icon != undefined ) || ( i?.checked != undefined ) } ).length > 0;
|
|
1440
|
-
|
|
1441
|
-
for( let item of items )
|
|
1442
|
-
{
|
|
1443
|
-
if( !item )
|
|
1444
|
-
{
|
|
1445
|
-
this._addSeparator( parentDom );
|
|
1446
|
-
continue;
|
|
1076
|
+
this._addSeparator( parentDom );
|
|
1077
|
+
continue;
|
|
1447
1078
|
}
|
|
1448
1079
|
|
|
1449
1080
|
const key = item.name ?? item;
|
|
@@ -2247,13 +1878,6 @@ class Calendar {
|
|
|
2247
1878
|
|
|
2248
1879
|
LX.Calendar = Calendar;
|
|
2249
1880
|
|
|
2250
|
-
function flushCss(element) {
|
|
2251
|
-
// By reading the offsetHeight property, we are forcing
|
|
2252
|
-
// the browser to flush the pending CSS changes (which it
|
|
2253
|
-
// does to ensure the value obtained is accurate).
|
|
2254
|
-
element.offsetHeight;
|
|
2255
|
-
}
|
|
2256
|
-
|
|
2257
1881
|
/**
|
|
2258
1882
|
* @class Tabs
|
|
2259
1883
|
*/
|
|
@@ -2379,7 +2003,7 @@ class Tabs {
|
|
|
2379
2003
|
this.thumb.style.transition = "none";
|
|
2380
2004
|
this.thumb.style.transform = "translate( " + ( tabEl.childIndex * tabEl.offsetWidth ) + "px )";
|
|
2381
2005
|
this.thumb.style.width = ( tabEl.offsetWidth ) + "px";
|
|
2382
|
-
flushCss( this.thumb );
|
|
2006
|
+
LX.flushCss( this.thumb );
|
|
2383
2007
|
this.thumb.style.transition = transition;
|
|
2384
2008
|
});
|
|
2385
2009
|
|
|
@@ -3493,7 +3117,7 @@ class CanvasCurve {
|
|
|
3493
3117
|
}
|
|
3494
3118
|
else
|
|
3495
3119
|
{
|
|
3496
|
-
LX.
|
|
3120
|
+
LX.drawSpline( ctx, values, element.smooth );
|
|
3497
3121
|
}
|
|
3498
3122
|
|
|
3499
3123
|
// Draw points
|
|
@@ -4435,254 +4059,6 @@ class CanvasMap2D {
|
|
|
4435
4059
|
|
|
4436
4060
|
LX.CanvasMap2D = CanvasMap2D;
|
|
4437
4061
|
|
|
4438
|
-
/*
|
|
4439
|
-
* Requests
|
|
4440
|
-
*/
|
|
4441
|
-
|
|
4442
|
-
Object.assign(LX, {
|
|
4443
|
-
|
|
4444
|
-
/**
|
|
4445
|
-
* Request file from url (it could be a binary, text, etc.). If you want a simplied version use
|
|
4446
|
-
* @method request
|
|
4447
|
-
* @param {Object} request object with all the parameters like data (for sending forms), dataType, success, error
|
|
4448
|
-
* @param {Function} on_complete
|
|
4449
|
-
**/
|
|
4450
|
-
request( request ) {
|
|
4451
|
-
|
|
4452
|
-
var dataType = request.dataType || "text";
|
|
4453
|
-
if(dataType == "json") //parse it locally
|
|
4454
|
-
dataType = "text";
|
|
4455
|
-
else if(dataType == "xml") //parse it locally
|
|
4456
|
-
dataType = "text";
|
|
4457
|
-
else if (dataType == "binary")
|
|
4458
|
-
{
|
|
4459
|
-
//request.mimeType = "text/plain; charset=x-user-defined";
|
|
4460
|
-
dataType = "arraybuffer";
|
|
4461
|
-
request.mimeType = "application/octet-stream";
|
|
4462
|
-
}
|
|
4463
|
-
|
|
4464
|
-
//regular case, use AJAX call
|
|
4465
|
-
var xhr = new XMLHttpRequest();
|
|
4466
|
-
xhr.open( request.data ? 'POST' : 'GET', request.url, true);
|
|
4467
|
-
if(dataType)
|
|
4468
|
-
xhr.responseType = dataType;
|
|
4469
|
-
if (request.mimeType)
|
|
4470
|
-
xhr.overrideMimeType( request.mimeType );
|
|
4471
|
-
if( request.nocache )
|
|
4472
|
-
xhr.setRequestHeader('Cache-Control', 'no-cache');
|
|
4473
|
-
|
|
4474
|
-
xhr.onload = function(load)
|
|
4475
|
-
{
|
|
4476
|
-
var response = this.response;
|
|
4477
|
-
if( this.status != 200)
|
|
4478
|
-
{
|
|
4479
|
-
var err = "Error " + this.status;
|
|
4480
|
-
if(request.error)
|
|
4481
|
-
request.error(err);
|
|
4482
|
-
return;
|
|
4483
|
-
}
|
|
4484
|
-
|
|
4485
|
-
if(request.dataType == "json") //chrome doesnt support json format
|
|
4486
|
-
{
|
|
4487
|
-
try
|
|
4488
|
-
{
|
|
4489
|
-
response = JSON.parse(response);
|
|
4490
|
-
}
|
|
4491
|
-
catch (err)
|
|
4492
|
-
{
|
|
4493
|
-
if(request.error)
|
|
4494
|
-
request.error(err);
|
|
4495
|
-
else
|
|
4496
|
-
throw err;
|
|
4497
|
-
}
|
|
4498
|
-
}
|
|
4499
|
-
else if(request.dataType == "xml")
|
|
4500
|
-
{
|
|
4501
|
-
try
|
|
4502
|
-
{
|
|
4503
|
-
var xmlparser = new DOMParser();
|
|
4504
|
-
response = xmlparser.parseFromString(response,"text/xml");
|
|
4505
|
-
}
|
|
4506
|
-
catch (err)
|
|
4507
|
-
{
|
|
4508
|
-
if(request.error)
|
|
4509
|
-
request.error(err);
|
|
4510
|
-
else
|
|
4511
|
-
throw err;
|
|
4512
|
-
}
|
|
4513
|
-
}
|
|
4514
|
-
if(request.success)
|
|
4515
|
-
request.success.call(this, response, this);
|
|
4516
|
-
};
|
|
4517
|
-
xhr.onerror = function(err) {
|
|
4518
|
-
if(request.error)
|
|
4519
|
-
request.error(err);
|
|
4520
|
-
};
|
|
4521
|
-
|
|
4522
|
-
var data = new FormData();
|
|
4523
|
-
if( request.data )
|
|
4524
|
-
{
|
|
4525
|
-
for( var i in request.data)
|
|
4526
|
-
data.append(i,request.data[ i ]);
|
|
4527
|
-
}
|
|
4528
|
-
|
|
4529
|
-
xhr.send( data );
|
|
4530
|
-
return xhr;
|
|
4531
|
-
},
|
|
4532
|
-
|
|
4533
|
-
/**
|
|
4534
|
-
* Request file from url
|
|
4535
|
-
* @method requestText
|
|
4536
|
-
* @param {String} url
|
|
4537
|
-
* @param {Function} onComplete
|
|
4538
|
-
* @param {Function} onError
|
|
4539
|
-
**/
|
|
4540
|
-
requestText( url, onComplete, onError ) {
|
|
4541
|
-
return this.request({ url: url, dataType:"text", success: onComplete, error: onError });
|
|
4542
|
-
},
|
|
4543
|
-
|
|
4544
|
-
/**
|
|
4545
|
-
* Request file from url
|
|
4546
|
-
* @method requestJSON
|
|
4547
|
-
* @param {String} url
|
|
4548
|
-
* @param {Function} onComplete
|
|
4549
|
-
* @param {Function} onError
|
|
4550
|
-
**/
|
|
4551
|
-
requestJSON( url, onComplete, onError ) {
|
|
4552
|
-
return this.request({ url: url, dataType:"json", success: onComplete, error: onError });
|
|
4553
|
-
},
|
|
4554
|
-
|
|
4555
|
-
/**
|
|
4556
|
-
* Request binary file from url
|
|
4557
|
-
* @method requestBinary
|
|
4558
|
-
* @param {String} url
|
|
4559
|
-
* @param {Function} onComplete
|
|
4560
|
-
* @param {Function} onError
|
|
4561
|
-
**/
|
|
4562
|
-
requestBinary( url, onComplete, onError ) {
|
|
4563
|
-
return this.request({ url: url, dataType:"binary", success: onComplete, error: onError });
|
|
4564
|
-
},
|
|
4565
|
-
|
|
4566
|
-
/**
|
|
4567
|
-
* Request script and inserts it in the DOM
|
|
4568
|
-
* @method requireScript
|
|
4569
|
-
* @param {String|Array} url the url of the script or an array containing several urls
|
|
4570
|
-
* @param {Function} onComplete
|
|
4571
|
-
* @param {Function} onError
|
|
4572
|
-
* @param {Function} onProgress (if several files are required, onProgress is called after every file is added to the DOM)
|
|
4573
|
-
**/
|
|
4574
|
-
requireScript( url, onComplete, onError, onProgress, version ) {
|
|
4575
|
-
|
|
4576
|
-
if(!url)
|
|
4577
|
-
throw("invalid URL");
|
|
4578
|
-
|
|
4579
|
-
if( url.constructor === String )
|
|
4580
|
-
url = [url];
|
|
4581
|
-
|
|
4582
|
-
var total = url.length;
|
|
4583
|
-
var loaded_scripts = [];
|
|
4584
|
-
|
|
4585
|
-
for( var i in url)
|
|
4586
|
-
{
|
|
4587
|
-
var script = document.createElement('script');
|
|
4588
|
-
script.num = i;
|
|
4589
|
-
script.type = 'text/javascript';
|
|
4590
|
-
script.src = url[ i ] + ( version ? "?version=" + version : "" );
|
|
4591
|
-
script.original_src = url[ i ];
|
|
4592
|
-
script.async = false;
|
|
4593
|
-
script.onload = function( e ) {
|
|
4594
|
-
total--;
|
|
4595
|
-
loaded_scripts.push(this);
|
|
4596
|
-
if(total)
|
|
4597
|
-
{
|
|
4598
|
-
if( onProgress )
|
|
4599
|
-
{
|
|
4600
|
-
onProgress( this.original_src, this.num );
|
|
4601
|
-
}
|
|
4602
|
-
}
|
|
4603
|
-
else if(onComplete)
|
|
4604
|
-
onComplete( loaded_scripts );
|
|
4605
|
-
};
|
|
4606
|
-
if(onError)
|
|
4607
|
-
script.onerror = function(err) {
|
|
4608
|
-
onError(err, this.original_src, this.num );
|
|
4609
|
-
};
|
|
4610
|
-
document.getElementsByTagName('head')[ 0 ].appendChild(script);
|
|
4611
|
-
}
|
|
4612
|
-
},
|
|
4613
|
-
|
|
4614
|
-
loadScriptSync( url ) {
|
|
4615
|
-
return new Promise((resolve, reject) => {
|
|
4616
|
-
const script = document.createElement( "script" );
|
|
4617
|
-
script.src = url;
|
|
4618
|
-
script.async = false;
|
|
4619
|
-
script.onload = () => resolve();
|
|
4620
|
-
script.onerror = () => reject(new Error(`Failed to load ${url}`));
|
|
4621
|
-
document.head.appendChild( script );
|
|
4622
|
-
});
|
|
4623
|
-
},
|
|
4624
|
-
|
|
4625
|
-
downloadURL( url, filename ) {
|
|
4626
|
-
|
|
4627
|
-
const fr = new FileReader();
|
|
4628
|
-
|
|
4629
|
-
const _download = function(_url) {
|
|
4630
|
-
var link = document.createElement('a');
|
|
4631
|
-
link.href = _url;
|
|
4632
|
-
link.download = filename;
|
|
4633
|
-
document.body.appendChild(link);
|
|
4634
|
-
link.click();
|
|
4635
|
-
document.body.removeChild(link);
|
|
4636
|
-
};
|
|
4637
|
-
|
|
4638
|
-
if( url.includes('http') )
|
|
4639
|
-
{
|
|
4640
|
-
LX.request({ url: url, dataType: 'blob', success: (f) => {
|
|
4641
|
-
fr.readAsDataURL( f );
|
|
4642
|
-
fr.onload = e => {
|
|
4643
|
-
_download(e.currentTarget.result);
|
|
4644
|
-
};
|
|
4645
|
-
} });
|
|
4646
|
-
}else
|
|
4647
|
-
{
|
|
4648
|
-
_download(url);
|
|
4649
|
-
}
|
|
4650
|
-
|
|
4651
|
-
},
|
|
4652
|
-
|
|
4653
|
-
downloadFile: function( filename, data, dataType ) {
|
|
4654
|
-
if(!data)
|
|
4655
|
-
{
|
|
4656
|
-
console.warn("No file provided to download");
|
|
4657
|
-
return;
|
|
4658
|
-
}
|
|
4659
|
-
|
|
4660
|
-
if(!dataType)
|
|
4661
|
-
{
|
|
4662
|
-
if(data.constructor === String )
|
|
4663
|
-
dataType = 'text/plain';
|
|
4664
|
-
else
|
|
4665
|
-
dataType = 'application/octet-stream';
|
|
4666
|
-
}
|
|
4667
|
-
|
|
4668
|
-
var file = null;
|
|
4669
|
-
if(data.constructor !== File && data.constructor !== Blob)
|
|
4670
|
-
file = new Blob( [ data ], {type : dataType});
|
|
4671
|
-
else
|
|
4672
|
-
file = data;
|
|
4673
|
-
|
|
4674
|
-
var url = URL.createObjectURL( file );
|
|
4675
|
-
var element = document.createElement("a");
|
|
4676
|
-
element.setAttribute('href', url);
|
|
4677
|
-
element.setAttribute('download', filename );
|
|
4678
|
-
element.style.display = 'none';
|
|
4679
|
-
document.body.appendChild(element);
|
|
4680
|
-
element.click();
|
|
4681
|
-
document.body.removeChild(element);
|
|
4682
|
-
setTimeout( function(){ URL.revokeObjectURL( url ); }, 1000*60 ); //wait one minute to revoke url
|
|
4683
|
-
}
|
|
4684
|
-
});
|
|
4685
|
-
|
|
4686
4062
|
Object.defineProperty(String.prototype, 'lastChar', {
|
|
4687
4063
|
get: function() { return this[ this.length - 1 ]; },
|
|
4688
4064
|
enumerable: true,
|
|
@@ -4731,8 +4107,8 @@ Element.prototype.ignore = function( eventName, callbackName ) {
|
|
|
4731
4107
|
callbackName = callbackName ?? ( "_on" + eventName );
|
|
4732
4108
|
const callback = this[ callbackName ];
|
|
4733
4109
|
this.removeEventListener( eventName, callback );
|
|
4734
|
-
};
|
|
4735
|
-
|
|
4110
|
+
};
|
|
4111
|
+
|
|
4736
4112
|
// icons.js @jxarco
|
|
4737
4113
|
|
|
4738
4114
|
const RAW_ICONS = {
|
|
@@ -4910,8 +4286,8 @@ LX.LucideIconAlias = {
|
|
|
4910
4286
|
"RotateRight": "RotateCw",
|
|
4911
4287
|
"RotateBack": "RotateCcw",
|
|
4912
4288
|
"RotateLeft": "RotateCcw",
|
|
4913
|
-
};
|
|
4914
|
-
|
|
4289
|
+
};
|
|
4290
|
+
|
|
4915
4291
|
// utils.js @jxarco
|
|
4916
4292
|
|
|
4917
4293
|
function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
|
|
@@ -4960,15 +4336,39 @@ function doAsync( fn, ms ) {
|
|
|
4960
4336
|
LX.doAsync = doAsync;
|
|
4961
4337
|
|
|
4962
4338
|
/**
|
|
4963
|
-
* @method
|
|
4964
|
-
* @description
|
|
4965
|
-
*
|
|
4339
|
+
* @method flushCss
|
|
4340
|
+
* @description By reading the offsetHeight property, we are forcing the browser to flush
|
|
4341
|
+
* the pending CSS changes (which it does to ensure the value obtained is accurate).
|
|
4342
|
+
* @param {HTMLElement} element
|
|
4966
4343
|
*/
|
|
4967
|
-
function
|
|
4344
|
+
function flushCss( element )
|
|
4968
4345
|
{
|
|
4969
|
-
|
|
4346
|
+
element.offsetHeight;
|
|
4347
|
+
}
|
|
4970
4348
|
|
|
4971
|
-
|
|
4349
|
+
LX.flushCss = flushCss;
|
|
4350
|
+
|
|
4351
|
+
/**
|
|
4352
|
+
* @method deleteElement
|
|
4353
|
+
* @param {HTMLElement} element
|
|
4354
|
+
*/
|
|
4355
|
+
function deleteElement( element )
|
|
4356
|
+
{
|
|
4357
|
+
if( element !== undefined ) element.remove();
|
|
4358
|
+
}
|
|
4359
|
+
|
|
4360
|
+
LX.deleteElement = deleteElement;
|
|
4361
|
+
|
|
4362
|
+
/**
|
|
4363
|
+
* @method getSupportedDOMName
|
|
4364
|
+
* @description Convert a text string to a valid DOM name
|
|
4365
|
+
* @param {String} text Original text
|
|
4366
|
+
*/
|
|
4367
|
+
function getSupportedDOMName( text )
|
|
4368
|
+
{
|
|
4369
|
+
console.assert( typeof text == "string", "getSupportedDOMName: Text is not a string!" );
|
|
4370
|
+
|
|
4371
|
+
let name = text.trim();
|
|
4972
4372
|
|
|
4973
4373
|
// Replace specific known symbols
|
|
4974
4374
|
name = name.replace( /@/g, '_at_' ).replace( /\+/g, '_plus_' ).replace( /\./g, '_dot_' );
|
|
@@ -5029,9 +4429,13 @@ LX.stripHTML = stripHTML;
|
|
|
5029
4429
|
* @param {Number|String} size
|
|
5030
4430
|
* @param {Number} total
|
|
5031
4431
|
*/
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
4432
|
+
function parsePixelSize( size, total )
|
|
4433
|
+
{
|
|
4434
|
+
// Assuming pixels..
|
|
4435
|
+
if( size.constructor === Number )
|
|
4436
|
+
{
|
|
4437
|
+
return size;
|
|
4438
|
+
}
|
|
5035
4439
|
|
|
5036
4440
|
if( size.constructor === String )
|
|
5037
4441
|
{
|
|
@@ -5069,7 +4473,7 @@ const parsePixelSize = ( size, total ) => {
|
|
|
5069
4473
|
}
|
|
5070
4474
|
|
|
5071
4475
|
throw( "Bad size format!" );
|
|
5072
|
-
}
|
|
4476
|
+
}
|
|
5073
4477
|
|
|
5074
4478
|
LX.parsePixelSize = parsePixelSize;
|
|
5075
4479
|
|
|
@@ -5332,7 +4736,7 @@ function measureRealWidth( value, paddingPlusMargin = 8 )
|
|
|
5332
4736
|
i.innerHTML = value;
|
|
5333
4737
|
document.body.appendChild( i );
|
|
5334
4738
|
var rect = i.getBoundingClientRect();
|
|
5335
|
-
LX.
|
|
4739
|
+
LX.deleteElement( i );
|
|
5336
4740
|
return rect.width + paddingPlusMargin;
|
|
5337
4741
|
}
|
|
5338
4742
|
|
|
@@ -5754,207 +5158,853 @@ function makeIcon( iconName, options = { } )
|
|
|
5754
5158
|
svg.classList.add( c );
|
|
5755
5159
|
} );
|
|
5756
5160
|
|
|
5757
|
-
const attrs = data[ 5 ].svgAttributes;
|
|
5758
|
-
attrs?.split( ' ' ).forEach( attr => {
|
|
5759
|
-
const t = attr.split( '=' );
|
|
5760
|
-
svg.setAttribute( t[ 0 ], t[ 1 ] );
|
|
5761
|
-
} );
|
|
5762
|
-
}
|
|
5161
|
+
const attrs = data[ 5 ].svgAttributes;
|
|
5162
|
+
attrs?.split( ' ' ).forEach( attr => {
|
|
5163
|
+
const t = attr.split( '=' );
|
|
5164
|
+
svg.setAttribute( t[ 0 ], t[ 1 ] );
|
|
5165
|
+
} );
|
|
5166
|
+
}
|
|
5167
|
+
|
|
5168
|
+
const path = document.createElement( "path" );
|
|
5169
|
+
path.setAttribute( "fill", "currentColor" );
|
|
5170
|
+
path.setAttribute( "d", data[ 4 ] );
|
|
5171
|
+
svg.appendChild( path );
|
|
5172
|
+
|
|
5173
|
+
if( data[ 5 ] )
|
|
5174
|
+
{
|
|
5175
|
+
const classes = data[ 5 ].pathClass;
|
|
5176
|
+
classes?.split( ' ' ).forEach( c => {
|
|
5177
|
+
path.classList.add( c );
|
|
5178
|
+
} );
|
|
5179
|
+
|
|
5180
|
+
const attrs = data[ 5 ].pathAttributes;
|
|
5181
|
+
attrs?.split( ' ' ).forEach( attr => {
|
|
5182
|
+
const t = attr.split( '=' );
|
|
5183
|
+
path.setAttribute( t[ 0 ], t[ 1 ] );
|
|
5184
|
+
} );
|
|
5185
|
+
}
|
|
5186
|
+
|
|
5187
|
+
const faLicense = `<!-- This icon might belong to a collection from Iconify - https://iconify.design/ - or !Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc. -->`;
|
|
5188
|
+
svg.innerHTML += faLicense;
|
|
5189
|
+
return _createIconFromSVG( svg );
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
5192
|
+
|
|
5193
|
+
// Fallback to Lucide icon
|
|
5194
|
+
console.assert( lucideData, `No existing icon named _${ iconName }_` );
|
|
5195
|
+
svg = lucide.createElement( lucideData, options );
|
|
5196
|
+
|
|
5197
|
+
return _createIconFromSVG( svg );
|
|
5198
|
+
}
|
|
5199
|
+
|
|
5200
|
+
LX.makeIcon = makeIcon;
|
|
5201
|
+
|
|
5202
|
+
/**
|
|
5203
|
+
* @method registerIcon
|
|
5204
|
+
* @description Register an SVG icon to LX.ICONS
|
|
5205
|
+
* @param {String} iconName
|
|
5206
|
+
* @param {String} svgString
|
|
5207
|
+
* @param {String} variant
|
|
5208
|
+
* @param {Array} aliases
|
|
5209
|
+
*/
|
|
5210
|
+
function registerIcon( iconName, svgString, variant = "none", aliases = [] )
|
|
5211
|
+
{
|
|
5212
|
+
const svg = new DOMParser().parseFromString( svgString, 'image/svg+xml' ).documentElement;
|
|
5213
|
+
const path = svg.querySelector( "path" );
|
|
5214
|
+
const viewBox = svg.getAttribute( "viewBox" ).split( ' ' );
|
|
5215
|
+
const pathData = path.getAttribute( 'd' );
|
|
5216
|
+
|
|
5217
|
+
let svgAttributes = [];
|
|
5218
|
+
let pathAttributes = [];
|
|
5219
|
+
|
|
5220
|
+
for( const attr of svg.attributes )
|
|
5221
|
+
{
|
|
5222
|
+
switch( attr.name )
|
|
5223
|
+
{
|
|
5224
|
+
case "transform":
|
|
5225
|
+
case "fill":
|
|
5226
|
+
case "stroke-width":
|
|
5227
|
+
case "stroke-linecap":
|
|
5228
|
+
case "stroke-linejoin":
|
|
5229
|
+
svgAttributes.push( `${ attr.name }=${ attr.value }` );
|
|
5230
|
+
break;
|
|
5231
|
+
}
|
|
5232
|
+
}
|
|
5233
|
+
|
|
5234
|
+
for( const attr of path.attributes )
|
|
5235
|
+
{
|
|
5236
|
+
switch( attr.name )
|
|
5237
|
+
{
|
|
5238
|
+
case "transform":
|
|
5239
|
+
case "fill":
|
|
5240
|
+
case "stroke-width":
|
|
5241
|
+
case "stroke-linecap":
|
|
5242
|
+
case "stroke-linejoin":
|
|
5243
|
+
pathAttributes.push( `${ attr.name }=${ attr.value }` );
|
|
5244
|
+
break;
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
|
|
5248
|
+
const iconData = [
|
|
5249
|
+
parseInt( viewBox[ 2 ] ),
|
|
5250
|
+
parseInt( viewBox[ 3 ] ),
|
|
5251
|
+
aliases,
|
|
5252
|
+
variant,
|
|
5253
|
+
pathData,
|
|
5254
|
+
{
|
|
5255
|
+
svgAttributes: svgAttributes.length ? svgAttributes.join( ' ' ) : null,
|
|
5256
|
+
pathAttributes: pathAttributes.length ? pathAttributes.join( ' ' ) : null
|
|
5257
|
+
}
|
|
5258
|
+
];
|
|
5259
|
+
|
|
5260
|
+
if( LX.ICONS[ iconName ] )
|
|
5261
|
+
{
|
|
5262
|
+
console.warn( `${ iconName } will be added/replaced in LX.ICONS` );
|
|
5263
|
+
}
|
|
5264
|
+
|
|
5265
|
+
LX.ICONS[ iconName ] = iconData;
|
|
5266
|
+
}
|
|
5267
|
+
|
|
5268
|
+
LX.registerIcon = registerIcon;
|
|
5269
|
+
|
|
5270
|
+
/**
|
|
5271
|
+
* @method registerCommandbarEntry
|
|
5272
|
+
* @description Adds an extra command bar entry
|
|
5273
|
+
* @param {String} name
|
|
5274
|
+
* @param {Function} callback
|
|
5275
|
+
*/
|
|
5276
|
+
function registerCommandbarEntry( name, callback )
|
|
5277
|
+
{
|
|
5278
|
+
LX.extraCommandbarEntries.push( { name, callback } );
|
|
5279
|
+
}
|
|
5280
|
+
|
|
5281
|
+
LX.registerCommandbarEntry = registerCommandbarEntry;
|
|
5282
|
+
|
|
5283
|
+
/*
|
|
5284
|
+
Dialog and Notification Elements
|
|
5285
|
+
*/
|
|
5286
|
+
|
|
5287
|
+
/**
|
|
5288
|
+
* @method message
|
|
5289
|
+
* @param {String} text
|
|
5290
|
+
* @param {String} title (Optional)
|
|
5291
|
+
* @param {Object} options
|
|
5292
|
+
* id: Id of the message dialog
|
|
5293
|
+
* position: Dialog position in screen [screen centered]
|
|
5294
|
+
* draggable: Dialog can be dragged [false]
|
|
5295
|
+
*/
|
|
5296
|
+
|
|
5297
|
+
function message( text, title, options = {} )
|
|
5298
|
+
{
|
|
5299
|
+
if( !text )
|
|
5300
|
+
{
|
|
5301
|
+
throw( "No message to show" );
|
|
5302
|
+
}
|
|
5303
|
+
|
|
5304
|
+
options.modal = true;
|
|
5305
|
+
|
|
5306
|
+
return new LX.Dialog( title, p => {
|
|
5307
|
+
p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
|
|
5308
|
+
}, options );
|
|
5309
|
+
}
|
|
5310
|
+
|
|
5311
|
+
LX.message = message;
|
|
5312
|
+
|
|
5313
|
+
/**
|
|
5314
|
+
* @method popup
|
|
5315
|
+
* @param {String} text
|
|
5316
|
+
* @param {String} title (Optional)
|
|
5317
|
+
* @param {Object} options
|
|
5318
|
+
* id: Id of the message dialog
|
|
5319
|
+
* timeout (Number): Delay time before it closes automatically (ms). Default: [3000]
|
|
5320
|
+
* position (Array): [x,y] Dialog position in screen. Default: [screen centered]
|
|
5321
|
+
* size (Array): [width, height]
|
|
5322
|
+
*/
|
|
5323
|
+
|
|
5324
|
+
function popup( text, title, options = {} )
|
|
5325
|
+
{
|
|
5326
|
+
if( !text )
|
|
5327
|
+
{
|
|
5328
|
+
throw("No message to show");
|
|
5329
|
+
}
|
|
5330
|
+
|
|
5331
|
+
options.size = options.size ?? [ "max-content", "auto" ];
|
|
5332
|
+
options.class = "lexpopup";
|
|
5333
|
+
|
|
5334
|
+
const time = options.timeout || 3000;
|
|
5335
|
+
const dialog = new LX.Dialog( title, p => {
|
|
5336
|
+
p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
|
|
5337
|
+
}, options );
|
|
5338
|
+
|
|
5339
|
+
setTimeout( () => {
|
|
5340
|
+
dialog.close();
|
|
5341
|
+
}, Math.max( time, 150 ) );
|
|
5342
|
+
|
|
5343
|
+
return dialog;
|
|
5344
|
+
}
|
|
5345
|
+
|
|
5346
|
+
LX.popup = popup;
|
|
5347
|
+
|
|
5348
|
+
/**
|
|
5349
|
+
* @method prompt
|
|
5350
|
+
* @param {String} text
|
|
5351
|
+
* @param {String} title (Optional)
|
|
5352
|
+
* @param {Object} options
|
|
5353
|
+
* id: Id of the prompt dialog
|
|
5354
|
+
* position: Dialog position in screen [screen centered]
|
|
5355
|
+
* draggable: Dialog can be dragged [false]
|
|
5356
|
+
* input: If false, no text input appears
|
|
5357
|
+
* accept: Accept text
|
|
5358
|
+
* required: Input has to be filled [true]. Default: false
|
|
5359
|
+
*/
|
|
5360
|
+
|
|
5361
|
+
function prompt( text, title, callback, options = {} )
|
|
5362
|
+
{
|
|
5363
|
+
options.modal = true;
|
|
5364
|
+
options.className = "prompt";
|
|
5365
|
+
|
|
5366
|
+
let value = "";
|
|
5367
|
+
|
|
5368
|
+
const dialog = new LX.Dialog( title, p => {
|
|
5369
|
+
|
|
5370
|
+
p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
|
|
5371
|
+
|
|
5372
|
+
if( options.input ?? true )
|
|
5373
|
+
{
|
|
5374
|
+
p.addText( null, options.input || value, v => value = v, { placeholder: "..." } );
|
|
5375
|
+
}
|
|
5376
|
+
|
|
5377
|
+
p.sameLine( 2 );
|
|
5378
|
+
|
|
5379
|
+
p.addButton(null, "Cancel", () => {if(options.on_cancel) options.on_cancel(); dialog.close();} );
|
|
5380
|
+
|
|
5381
|
+
p.addButton( null, options.accept || "Continue", () => {
|
|
5382
|
+
if( options.required && value === '' )
|
|
5383
|
+
{
|
|
5384
|
+
text += text.includes("You must fill the input text.") ? "": "\nYou must fill the input text.";
|
|
5385
|
+
dialog.close();
|
|
5386
|
+
prompt( text, title, callback, options );
|
|
5387
|
+
}
|
|
5388
|
+
else
|
|
5389
|
+
{
|
|
5390
|
+
if( callback ) callback.call( this, value );
|
|
5391
|
+
dialog.close();
|
|
5392
|
+
}
|
|
5393
|
+
}, { buttonClass: "primary" });
|
|
5394
|
+
|
|
5395
|
+
}, options );
|
|
5396
|
+
|
|
5397
|
+
// Focus text prompt
|
|
5398
|
+
if( options.input ?? true )
|
|
5399
|
+
{
|
|
5400
|
+
dialog.root.querySelector( 'input' ).focus();
|
|
5401
|
+
}
|
|
5402
|
+
|
|
5403
|
+
return dialog;
|
|
5404
|
+
}
|
|
5405
|
+
|
|
5406
|
+
LX.prompt = prompt;
|
|
5407
|
+
|
|
5408
|
+
/**
|
|
5409
|
+
* @method toast
|
|
5410
|
+
* @param {String} title
|
|
5411
|
+
* @param {String} description (Optional)
|
|
5412
|
+
* @param {Object} options
|
|
5413
|
+
* action: Data of the custom action { name, callback }
|
|
5414
|
+
* closable: Allow closing the toast
|
|
5415
|
+
* timeout: Time in which the toast closed automatically, in ms. -1 means persistent. [3000]
|
|
5416
|
+
*/
|
|
5417
|
+
|
|
5418
|
+
function toast( title, description, options = {} )
|
|
5419
|
+
{
|
|
5420
|
+
if( !title )
|
|
5421
|
+
{
|
|
5422
|
+
throw( "The toast needs at least a title!" );
|
|
5423
|
+
}
|
|
5424
|
+
|
|
5425
|
+
console.assert( this.notifications );
|
|
5426
|
+
|
|
5427
|
+
const toast = document.createElement( "li" );
|
|
5428
|
+
toast.className = "lextoast";
|
|
5429
|
+
toast.style.translate = "0 calc(100% + 30px)";
|
|
5430
|
+
this.notifications.prepend( toast );
|
|
5431
|
+
|
|
5432
|
+
LX.doAsync( () => {
|
|
5433
|
+
|
|
5434
|
+
if( this.notifications.offsetWidth > this.notifications.iWidth )
|
|
5435
|
+
{
|
|
5436
|
+
this.notifications.iWidth = Math.min( this.notifications.offsetWidth, 480 );
|
|
5437
|
+
this.notifications.style.width = this.notifications.iWidth + "px";
|
|
5438
|
+
}
|
|
5439
|
+
|
|
5440
|
+
toast.dataset[ "open" ] = true;
|
|
5441
|
+
}, 10 );
|
|
5442
|
+
|
|
5443
|
+
const content = document.createElement( "div" );
|
|
5444
|
+
content.className = "lextoastcontent";
|
|
5445
|
+
toast.appendChild( content );
|
|
5446
|
+
|
|
5447
|
+
const titleContent = document.createElement( "div" );
|
|
5448
|
+
titleContent.className = "title";
|
|
5449
|
+
titleContent.innerHTML = title;
|
|
5450
|
+
content.appendChild( titleContent );
|
|
5451
|
+
|
|
5452
|
+
if( description )
|
|
5453
|
+
{
|
|
5454
|
+
const desc = document.createElement( "div" );
|
|
5455
|
+
desc.className = "desc";
|
|
5456
|
+
desc.innerHTML = description;
|
|
5457
|
+
content.appendChild( desc );
|
|
5458
|
+
}
|
|
5459
|
+
|
|
5460
|
+
if( options.action )
|
|
5461
|
+
{
|
|
5462
|
+
const panel = new LX.Panel();
|
|
5463
|
+
panel.addButton(null, options.action.name ?? "Accept", options.action.callback.bind( this, toast ), { width: "auto", maxWidth: "150px", className: "right", buttonClass: "border" });
|
|
5464
|
+
toast.appendChild( panel.root.childNodes[ 0 ] );
|
|
5465
|
+
}
|
|
5466
|
+
|
|
5467
|
+
const that = this;
|
|
5468
|
+
|
|
5469
|
+
toast.close = function() {
|
|
5470
|
+
this.dataset[ "closed" ] = true;
|
|
5471
|
+
LX.doAsync( () => {
|
|
5472
|
+
this.remove();
|
|
5473
|
+
if( !that.notifications.childElementCount )
|
|
5474
|
+
{
|
|
5475
|
+
that.notifications.style.width = "unset";
|
|
5476
|
+
that.notifications.iWidth = 0;
|
|
5477
|
+
}
|
|
5478
|
+
}, 500 );
|
|
5479
|
+
};
|
|
5480
|
+
|
|
5481
|
+
if( options.closable ?? true )
|
|
5482
|
+
{
|
|
5483
|
+
const closeIcon = LX.makeIcon( "X", { iconClass: "closer" } );
|
|
5484
|
+
closeIcon.addEventListener( "click", () => {
|
|
5485
|
+
toast.close();
|
|
5486
|
+
} );
|
|
5487
|
+
toast.appendChild( closeIcon );
|
|
5488
|
+
}
|
|
5489
|
+
|
|
5490
|
+
const timeout = options.timeout ?? 3000;
|
|
5491
|
+
|
|
5492
|
+
if( timeout != -1 )
|
|
5493
|
+
{
|
|
5494
|
+
LX.doAsync( () => {
|
|
5495
|
+
toast.close();
|
|
5496
|
+
}, timeout );
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5499
|
+
|
|
5500
|
+
LX.toast = toast;
|
|
5501
|
+
|
|
5502
|
+
/**
|
|
5503
|
+
* @method badge
|
|
5504
|
+
* @param {String} text
|
|
5505
|
+
* @param {String} className
|
|
5506
|
+
* @param {Object} options
|
|
5507
|
+
* style: Style attributes to override
|
|
5508
|
+
* asElement: Returns the badge as HTMLElement [false]
|
|
5509
|
+
*/
|
|
5510
|
+
|
|
5511
|
+
function badge( text, className, options = {} )
|
|
5512
|
+
{
|
|
5513
|
+
const container = document.createElement( "div" );
|
|
5514
|
+
container.innerHTML = text;
|
|
5515
|
+
container.className = "lexbadge " + ( className ?? "" );
|
|
5516
|
+
Object.assign( container.style, options.style ?? {} );
|
|
5517
|
+
return ( options.asElement ?? false ) ? container : container.outerHTML;
|
|
5518
|
+
}
|
|
5519
|
+
|
|
5520
|
+
LX.badge = badge;
|
|
5521
|
+
|
|
5522
|
+
/**
|
|
5523
|
+
* @method makeElement
|
|
5524
|
+
* @param {String} htmlType
|
|
5525
|
+
* @param {String} className
|
|
5526
|
+
* @param {String} innerHTML
|
|
5527
|
+
* @param {HTMLElement} parent
|
|
5528
|
+
* @param {Object} overrideStyle
|
|
5529
|
+
*/
|
|
5530
|
+
|
|
5531
|
+
function makeElement( htmlType, className, innerHTML, parent, overrideStyle = {} )
|
|
5532
|
+
{
|
|
5533
|
+
const element = document.createElement( htmlType );
|
|
5534
|
+
element.className = className ?? "";
|
|
5535
|
+
element.innerHTML = innerHTML ?? "";
|
|
5536
|
+
Object.assign( element.style, overrideStyle );
|
|
5537
|
+
|
|
5538
|
+
if( parent )
|
|
5539
|
+
{
|
|
5540
|
+
if( parent.attach ) // Use attach method if possible
|
|
5541
|
+
{
|
|
5542
|
+
parent.attach( element );
|
|
5543
|
+
}
|
|
5544
|
+
else // its a native HTMLElement
|
|
5545
|
+
{
|
|
5546
|
+
parent.appendChild( element );
|
|
5547
|
+
}
|
|
5548
|
+
}
|
|
5549
|
+
|
|
5550
|
+
return element;
|
|
5551
|
+
}
|
|
5552
|
+
|
|
5553
|
+
LX.makeElement = makeElement;
|
|
5554
|
+
|
|
5555
|
+
/**
|
|
5556
|
+
* @method makeContainer
|
|
5557
|
+
* @param {Array} size
|
|
5558
|
+
* @param {String} className
|
|
5559
|
+
* @param {String} innerHTML
|
|
5560
|
+
* @param {HTMLElement} parent
|
|
5561
|
+
* @param {Object} overrideStyle
|
|
5562
|
+
*/
|
|
5563
|
+
|
|
5564
|
+
function makeContainer( size, className, innerHTML, parent, overrideStyle = {} )
|
|
5565
|
+
{
|
|
5566
|
+
const container = LX.makeElement( "div", "lexcontainer " + ( className ?? "" ), innerHTML, parent, overrideStyle );
|
|
5567
|
+
container.style.width = size && size[ 0 ] ? size[ 0 ] : "100%";
|
|
5568
|
+
container.style.height = size && size[ 1 ] ? size[ 1 ] : "100%";
|
|
5569
|
+
return container;
|
|
5570
|
+
}
|
|
5571
|
+
|
|
5572
|
+
LX.makeContainer = makeContainer;
|
|
5573
|
+
|
|
5574
|
+
/**
|
|
5575
|
+
* @method asTooltip
|
|
5576
|
+
* @param {HTMLElement} trigger
|
|
5577
|
+
* @param {String} content
|
|
5578
|
+
* @param {Object} options
|
|
5579
|
+
* side: Side of the tooltip
|
|
5580
|
+
* offset: Tooltip margin offset
|
|
5581
|
+
* active: Tooltip active by default [true]
|
|
5582
|
+
*/
|
|
5583
|
+
|
|
5584
|
+
function asTooltip( trigger, content, options = {} )
|
|
5585
|
+
{
|
|
5586
|
+
console.assert( trigger, "You need a trigger to generate a tooltip!" );
|
|
5587
|
+
|
|
5588
|
+
trigger.dataset[ "disableTooltip" ] = !( options.active ?? true );
|
|
5589
|
+
|
|
5590
|
+
let tooltipDom = null;
|
|
5591
|
+
|
|
5592
|
+
trigger.addEventListener( "mouseenter", function(e) {
|
|
5593
|
+
|
|
5594
|
+
if( trigger.dataset[ "disableTooltip" ] == "true" )
|
|
5595
|
+
{
|
|
5596
|
+
return;
|
|
5597
|
+
}
|
|
5598
|
+
|
|
5599
|
+
LX.root.querySelectorAll( ".lextooltip" ).forEach( e => e.remove() );
|
|
5600
|
+
|
|
5601
|
+
tooltipDom = document.createElement( "div" );
|
|
5602
|
+
tooltipDom.className = "lextooltip";
|
|
5603
|
+
tooltipDom.innerHTML = content;
|
|
5604
|
+
|
|
5605
|
+
LX.doAsync( () => {
|
|
5606
|
+
|
|
5607
|
+
const position = [ 0, 0 ];
|
|
5608
|
+
const rect = this.getBoundingClientRect();
|
|
5609
|
+
const offset = options.offset ?? 6;
|
|
5610
|
+
let alignWidth = true;
|
|
5611
|
+
|
|
5612
|
+
switch( options.side ?? "top" )
|
|
5613
|
+
{
|
|
5614
|
+
case "left":
|
|
5615
|
+
position[ 0 ] += ( rect.x - tooltipDom.offsetWidth - offset );
|
|
5616
|
+
alignWidth = false;
|
|
5617
|
+
break;
|
|
5618
|
+
case "right":
|
|
5619
|
+
position[ 0 ] += ( rect.x + rect.width + offset );
|
|
5620
|
+
alignWidth = false;
|
|
5621
|
+
break;
|
|
5622
|
+
case "top":
|
|
5623
|
+
position[ 1 ] += ( rect.y - tooltipDom.offsetHeight - offset );
|
|
5624
|
+
alignWidth = true;
|
|
5625
|
+
break;
|
|
5626
|
+
case "bottom":
|
|
5627
|
+
position[ 1 ] += ( rect.y + rect.height + offset );
|
|
5628
|
+
alignWidth = true;
|
|
5629
|
+
break;
|
|
5630
|
+
}
|
|
5631
|
+
|
|
5632
|
+
if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - tooltipDom.offsetWidth * 0.5; }
|
|
5633
|
+
else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - tooltipDom.offsetHeight * 0.5; }
|
|
5634
|
+
|
|
5635
|
+
// Avoid collisions
|
|
5636
|
+
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - tooltipDom.offsetWidth - 4 );
|
|
5637
|
+
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - tooltipDom.offsetHeight - 4 );
|
|
5638
|
+
|
|
5639
|
+
tooltipDom.style.left = `${ position[ 0 ] }px`;
|
|
5640
|
+
tooltipDom.style.top = `${ position[ 1 ] }px`;
|
|
5641
|
+
} );
|
|
5642
|
+
|
|
5643
|
+
LX.root.appendChild( tooltipDom );
|
|
5644
|
+
} );
|
|
5645
|
+
|
|
5646
|
+
trigger.addEventListener( "mouseleave", function(e) {
|
|
5647
|
+
if( tooltipDom )
|
|
5648
|
+
{
|
|
5649
|
+
tooltipDom.remove();
|
|
5650
|
+
}
|
|
5651
|
+
} );
|
|
5652
|
+
}
|
|
5653
|
+
|
|
5654
|
+
LX.asTooltip = asTooltip;
|
|
5655
|
+
|
|
5656
|
+
/*
|
|
5657
|
+
* Requests
|
|
5658
|
+
*/
|
|
5659
|
+
|
|
5660
|
+
Object.assign(LX, {
|
|
5661
|
+
|
|
5662
|
+
/**
|
|
5663
|
+
* Request file from url (it could be a binary, text, etc.). If you want a simplied version use
|
|
5664
|
+
* @method request
|
|
5665
|
+
* @param {Object} request object with all the parameters like data (for sending forms), dataType, success, error
|
|
5666
|
+
* @param {Function} on_complete
|
|
5667
|
+
**/
|
|
5668
|
+
request( request ) {
|
|
5669
|
+
|
|
5670
|
+
var dataType = request.dataType || "text";
|
|
5671
|
+
if(dataType == "json") //parse it locally
|
|
5672
|
+
dataType = "text";
|
|
5673
|
+
else if(dataType == "xml") //parse it locally
|
|
5674
|
+
dataType = "text";
|
|
5675
|
+
else if (dataType == "binary")
|
|
5676
|
+
{
|
|
5677
|
+
//request.mimeType = "text/plain; charset=x-user-defined";
|
|
5678
|
+
dataType = "arraybuffer";
|
|
5679
|
+
request.mimeType = "application/octet-stream";
|
|
5680
|
+
}
|
|
5681
|
+
|
|
5682
|
+
//regular case, use AJAX call
|
|
5683
|
+
var xhr = new XMLHttpRequest();
|
|
5684
|
+
xhr.open( request.data ? 'POST' : 'GET', request.url, true);
|
|
5685
|
+
if(dataType)
|
|
5686
|
+
xhr.responseType = dataType;
|
|
5687
|
+
if (request.mimeType)
|
|
5688
|
+
xhr.overrideMimeType( request.mimeType );
|
|
5689
|
+
if( request.nocache )
|
|
5690
|
+
xhr.setRequestHeader('Cache-Control', 'no-cache');
|
|
5691
|
+
|
|
5692
|
+
xhr.onload = function(load)
|
|
5693
|
+
{
|
|
5694
|
+
var response = this.response;
|
|
5695
|
+
if( this.status != 200)
|
|
5696
|
+
{
|
|
5697
|
+
var err = "Error " + this.status;
|
|
5698
|
+
if(request.error)
|
|
5699
|
+
request.error(err);
|
|
5700
|
+
return;
|
|
5701
|
+
}
|
|
5702
|
+
|
|
5703
|
+
if(request.dataType == "json") //chrome doesnt support json format
|
|
5704
|
+
{
|
|
5705
|
+
try
|
|
5706
|
+
{
|
|
5707
|
+
response = JSON.parse(response);
|
|
5708
|
+
}
|
|
5709
|
+
catch (err)
|
|
5710
|
+
{
|
|
5711
|
+
if(request.error)
|
|
5712
|
+
request.error(err);
|
|
5713
|
+
else
|
|
5714
|
+
throw err;
|
|
5715
|
+
}
|
|
5716
|
+
}
|
|
5717
|
+
else if(request.dataType == "xml")
|
|
5718
|
+
{
|
|
5719
|
+
try
|
|
5720
|
+
{
|
|
5721
|
+
var xmlparser = new DOMParser();
|
|
5722
|
+
response = xmlparser.parseFromString(response,"text/xml");
|
|
5723
|
+
}
|
|
5724
|
+
catch (err)
|
|
5725
|
+
{
|
|
5726
|
+
if(request.error)
|
|
5727
|
+
request.error(err);
|
|
5728
|
+
else
|
|
5729
|
+
throw err;
|
|
5730
|
+
}
|
|
5731
|
+
}
|
|
5732
|
+
if(request.success)
|
|
5733
|
+
request.success.call(this, response, this);
|
|
5734
|
+
};
|
|
5735
|
+
xhr.onerror = function(err) {
|
|
5736
|
+
if(request.error)
|
|
5737
|
+
request.error(err);
|
|
5738
|
+
};
|
|
5739
|
+
|
|
5740
|
+
var data = new FormData();
|
|
5741
|
+
if( request.data )
|
|
5742
|
+
{
|
|
5743
|
+
for( var i in request.data)
|
|
5744
|
+
data.append(i,request.data[ i ]);
|
|
5745
|
+
}
|
|
5746
|
+
|
|
5747
|
+
xhr.send( data );
|
|
5748
|
+
return xhr;
|
|
5749
|
+
},
|
|
5750
|
+
|
|
5751
|
+
/**
|
|
5752
|
+
* Request file from url
|
|
5753
|
+
* @method requestText
|
|
5754
|
+
* @param {String} url
|
|
5755
|
+
* @param {Function} onComplete
|
|
5756
|
+
* @param {Function} onError
|
|
5757
|
+
**/
|
|
5758
|
+
requestText( url, onComplete, onError ) {
|
|
5759
|
+
return this.request({ url: url, dataType:"text", success: onComplete, error: onError });
|
|
5760
|
+
},
|
|
5761
|
+
|
|
5762
|
+
/**
|
|
5763
|
+
* Request file from url
|
|
5764
|
+
* @method requestJSON
|
|
5765
|
+
* @param {String} url
|
|
5766
|
+
* @param {Function} onComplete
|
|
5767
|
+
* @param {Function} onError
|
|
5768
|
+
**/
|
|
5769
|
+
requestJSON( url, onComplete, onError ) {
|
|
5770
|
+
return this.request({ url: url, dataType:"json", success: onComplete, error: onError });
|
|
5771
|
+
},
|
|
5772
|
+
|
|
5773
|
+
/**
|
|
5774
|
+
* Request binary file from url
|
|
5775
|
+
* @method requestBinary
|
|
5776
|
+
* @param {String} url
|
|
5777
|
+
* @param {Function} onComplete
|
|
5778
|
+
* @param {Function} onError
|
|
5779
|
+
**/
|
|
5780
|
+
requestBinary( url, onComplete, onError ) {
|
|
5781
|
+
return this.request({ url: url, dataType:"binary", success: onComplete, error: onError });
|
|
5782
|
+
},
|
|
5783
|
+
|
|
5784
|
+
/**
|
|
5785
|
+
* Request script and inserts it in the DOM
|
|
5786
|
+
* @method requireScript
|
|
5787
|
+
* @param {String|Array} url the url of the script or an array containing several urls
|
|
5788
|
+
* @param {Function} onComplete
|
|
5789
|
+
* @param {Function} onError
|
|
5790
|
+
* @param {Function} onProgress (if several files are required, onProgress is called after every file is added to the DOM)
|
|
5791
|
+
**/
|
|
5792
|
+
requireScript( url, onComplete, onError, onProgress, version ) {
|
|
5763
5793
|
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
path.setAttribute( "d", data[ 4 ] );
|
|
5767
|
-
svg.appendChild( path );
|
|
5794
|
+
if(!url)
|
|
5795
|
+
throw("invalid URL");
|
|
5768
5796
|
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
const classes = data[ 5 ].pathClass;
|
|
5772
|
-
classes?.split( ' ' ).forEach( c => {
|
|
5773
|
-
path.classList.add( c );
|
|
5774
|
-
} );
|
|
5797
|
+
if( url.constructor === String )
|
|
5798
|
+
url = [url];
|
|
5775
5799
|
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
const t = attr.split( '=' );
|
|
5779
|
-
path.setAttribute( t[ 0 ], t[ 1 ] );
|
|
5780
|
-
} );
|
|
5781
|
-
}
|
|
5800
|
+
var total = url.length;
|
|
5801
|
+
var loaded_scripts = [];
|
|
5782
5802
|
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5803
|
+
for( var i in url)
|
|
5804
|
+
{
|
|
5805
|
+
var script = document.createElement('script');
|
|
5806
|
+
script.num = i;
|
|
5807
|
+
script.type = 'text/javascript';
|
|
5808
|
+
script.src = url[ i ] + ( version ? "?version=" + version : "" );
|
|
5809
|
+
script.original_src = url[ i ];
|
|
5810
|
+
script.async = false;
|
|
5811
|
+
script.onload = function( e ) {
|
|
5812
|
+
total--;
|
|
5813
|
+
loaded_scripts.push(this);
|
|
5814
|
+
if(total)
|
|
5815
|
+
{
|
|
5816
|
+
if( onProgress )
|
|
5817
|
+
{
|
|
5818
|
+
onProgress( this.original_src, this.num );
|
|
5819
|
+
}
|
|
5820
|
+
}
|
|
5821
|
+
else if(onComplete)
|
|
5822
|
+
onComplete( loaded_scripts );
|
|
5823
|
+
};
|
|
5824
|
+
if(onError)
|
|
5825
|
+
script.onerror = function(err) {
|
|
5826
|
+
onError(err, this.original_src, this.num );
|
|
5827
|
+
};
|
|
5828
|
+
document.getElementsByTagName('head')[ 0 ].appendChild(script);
|
|
5786
5829
|
}
|
|
5787
|
-
}
|
|
5788
|
-
|
|
5789
|
-
// Fallback to Lucide icon
|
|
5790
|
-
console.assert( lucideData, `No existing icon named _${ iconName }_` );
|
|
5791
|
-
svg = lucide.createElement( lucideData, options );
|
|
5830
|
+
},
|
|
5792
5831
|
|
|
5793
|
-
|
|
5794
|
-
|
|
5832
|
+
loadScriptSync( url ) {
|
|
5833
|
+
return new Promise((resolve, reject) => {
|
|
5834
|
+
const script = document.createElement( "script" );
|
|
5835
|
+
script.src = url;
|
|
5836
|
+
script.async = false;
|
|
5837
|
+
script.onload = () => resolve();
|
|
5838
|
+
script.onerror = () => reject(new Error(`Failed to load ${url}`));
|
|
5839
|
+
document.head.appendChild( script );
|
|
5840
|
+
});
|
|
5841
|
+
},
|
|
5795
5842
|
|
|
5796
|
-
|
|
5843
|
+
downloadURL( url, filename ) {
|
|
5797
5844
|
|
|
5798
|
-
|
|
5799
|
-
* @method registerIcon
|
|
5800
|
-
* @description Register an SVG icon to LX.ICONS
|
|
5801
|
-
* @param {String} iconName
|
|
5802
|
-
* @param {String} svgString
|
|
5803
|
-
* @param {String} variant
|
|
5804
|
-
* @param {Array} aliases
|
|
5805
|
-
*/
|
|
5806
|
-
function registerIcon( iconName, svgString, variant = "none", aliases = [] )
|
|
5807
|
-
{
|
|
5808
|
-
const svg = new DOMParser().parseFromString( svgString, 'image/svg+xml' ).documentElement;
|
|
5809
|
-
const path = svg.querySelector( "path" );
|
|
5810
|
-
const viewBox = svg.getAttribute( "viewBox" ).split( ' ' );
|
|
5811
|
-
const pathData = path.getAttribute( 'd' );
|
|
5845
|
+
const fr = new FileReader();
|
|
5812
5846
|
|
|
5813
|
-
|
|
5814
|
-
|
|
5847
|
+
const _download = function(_url) {
|
|
5848
|
+
var link = document.createElement('a');
|
|
5849
|
+
link.href = _url;
|
|
5850
|
+
link.download = filename;
|
|
5851
|
+
document.body.appendChild(link);
|
|
5852
|
+
link.click();
|
|
5853
|
+
document.body.removeChild(link);
|
|
5854
|
+
};
|
|
5815
5855
|
|
|
5816
|
-
|
|
5817
|
-
{
|
|
5818
|
-
switch( attr.name )
|
|
5856
|
+
if( url.includes('http') )
|
|
5819
5857
|
{
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5858
|
+
LX.request({ url: url, dataType: 'blob', success: (f) => {
|
|
5859
|
+
fr.readAsDataURL( f );
|
|
5860
|
+
fr.onload = e => {
|
|
5861
|
+
_download(e.currentTarget.result);
|
|
5862
|
+
};
|
|
5863
|
+
} });
|
|
5864
|
+
}else
|
|
5865
|
+
{
|
|
5866
|
+
_download(url);
|
|
5827
5867
|
}
|
|
5828
|
-
}
|
|
5829
5868
|
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5869
|
+
},
|
|
5870
|
+
|
|
5871
|
+
downloadFile: function( filename, data, dataType ) {
|
|
5872
|
+
if(!data)
|
|
5833
5873
|
{
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
case "stroke-width":
|
|
5837
|
-
case "stroke-linecap":
|
|
5838
|
-
case "stroke-linejoin":
|
|
5839
|
-
pathAttributes.push( `${ attr.name }=${ attr.value }` );
|
|
5840
|
-
break;
|
|
5874
|
+
console.warn("No file provided to download");
|
|
5875
|
+
return;
|
|
5841
5876
|
}
|
|
5842
|
-
}
|
|
5843
5877
|
|
|
5844
|
-
|
|
5845
|
-
parseInt( viewBox[ 2 ] ),
|
|
5846
|
-
parseInt( viewBox[ 3 ] ),
|
|
5847
|
-
aliases,
|
|
5848
|
-
variant,
|
|
5849
|
-
pathData,
|
|
5878
|
+
if(!dataType)
|
|
5850
5879
|
{
|
|
5851
|
-
|
|
5852
|
-
|
|
5880
|
+
if(data.constructor === String )
|
|
5881
|
+
dataType = 'text/plain';
|
|
5882
|
+
else
|
|
5883
|
+
dataType = 'application/octet-stream';
|
|
5853
5884
|
}
|
|
5854
|
-
];
|
|
5855
5885
|
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5886
|
+
var file = null;
|
|
5887
|
+
if(data.constructor !== File && data.constructor !== Blob)
|
|
5888
|
+
file = new Blob( [ data ], {type : dataType});
|
|
5889
|
+
else
|
|
5890
|
+
file = data;
|
|
5891
|
+
|
|
5892
|
+
var url = URL.createObjectURL( file );
|
|
5893
|
+
var element = document.createElement("a");
|
|
5894
|
+
element.setAttribute('href', url);
|
|
5895
|
+
element.setAttribute('download', filename );
|
|
5896
|
+
element.style.display = 'none';
|
|
5897
|
+
document.body.appendChild(element);
|
|
5898
|
+
element.click();
|
|
5899
|
+
document.body.removeChild(element);
|
|
5900
|
+
setTimeout( function(){ URL.revokeObjectURL( url ); }, 1000*60 ); //wait one minute to revoke url
|
|
5859
5901
|
}
|
|
5902
|
+
});
|
|
5860
5903
|
|
|
5861
|
-
|
|
5904
|
+
/**
|
|
5905
|
+
* @method compareThreshold
|
|
5906
|
+
* @param {String} url
|
|
5907
|
+
* @param {Function} onComplete
|
|
5908
|
+
* @param {Function} onError
|
|
5909
|
+
**/
|
|
5910
|
+
function compareThreshold( v, p, n, t )
|
|
5911
|
+
{
|
|
5912
|
+
return Math.abs( v - p ) >= t || Math.abs( v - n ) >= t;
|
|
5862
5913
|
}
|
|
5863
5914
|
|
|
5864
|
-
LX.
|
|
5915
|
+
LX.compareThreshold = compareThreshold;
|
|
5865
5916
|
|
|
5866
5917
|
/**
|
|
5867
|
-
* @method
|
|
5868
|
-
* @
|
|
5869
|
-
* @param {
|
|
5870
|
-
* @param {Function}
|
|
5871
|
-
|
|
5872
|
-
function
|
|
5918
|
+
* @method compareThresholdRange
|
|
5919
|
+
* @param {String} url
|
|
5920
|
+
* @param {Function} onComplete
|
|
5921
|
+
* @param {Function} onError
|
|
5922
|
+
**/
|
|
5923
|
+
function compareThresholdRange( v0, v1, t0, t1 )
|
|
5873
5924
|
{
|
|
5874
|
-
|
|
5925
|
+
return v0 >= t0 && v0 <= t1 || v1 >= t0 && v1 <= t1 || v0 <= t0 && v1 >= t1;
|
|
5875
5926
|
}
|
|
5876
5927
|
|
|
5877
|
-
LX.
|
|
5928
|
+
LX.compareThresholdRange = compareThresholdRange;
|
|
5878
5929
|
|
|
5879
5930
|
/**
|
|
5880
|
-
*
|
|
5881
|
-
* @
|
|
5882
|
-
* @
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
// does to ensure the value obtained is accurate).
|
|
5894
|
-
element.offsetHeight;
|
|
5895
|
-
},
|
|
5896
|
-
getControlPoints( x0, y0, x1, y1, x2, y2, t ) {
|
|
5897
|
-
|
|
5898
|
-
// x0,y0,x1,y1 are the coordinates of the end (knot) pts of this segment
|
|
5899
|
-
// x2,y2 is the next knot -- not connected here but needed to calculate p2
|
|
5900
|
-
// p1 is the control point calculated here, from x1 back toward x0.
|
|
5901
|
-
// p2 is the next control point, calculated here and returned to become the
|
|
5902
|
-
// next segment's p1.
|
|
5903
|
-
// t is the 'tension' which controls how far the control points spread.
|
|
5931
|
+
* @method getControlPoints
|
|
5932
|
+
* @param {String} url
|
|
5933
|
+
* @param {Function} onComplete
|
|
5934
|
+
* @param {Function} onError
|
|
5935
|
+
**/
|
|
5936
|
+
function getControlPoints( x0, y0, x1, y1, x2, y2, t )
|
|
5937
|
+
{
|
|
5938
|
+
// x0,y0,x1,y1 are the coordinates of the end (knot) pts of this segment
|
|
5939
|
+
// x2,y2 is the next knot -- not connected here but needed to calculate p2
|
|
5940
|
+
// p1 is the control point calculated here, from x1 back toward x0.
|
|
5941
|
+
// p2 is the next control point, calculated here and returned to become the
|
|
5942
|
+
// next segment's p1.
|
|
5943
|
+
// t is the 'tension' which controls how far the control points spread.
|
|
5904
5944
|
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5945
|
+
// Scaling factors: distances from this knot to the previous and following knots.
|
|
5946
|
+
var d01=Math.sqrt(Math.pow(x1-x0,2)+Math.pow(y1-y0,2));
|
|
5947
|
+
var d12=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
|
|
5908
5948
|
|
|
5909
|
-
|
|
5910
|
-
|
|
5949
|
+
var fa=t*d01/(d01+d12);
|
|
5950
|
+
var fb=t-fa;
|
|
5911
5951
|
|
|
5912
|
-
|
|
5913
|
-
|
|
5952
|
+
var p1x=x1+fa*(x0-x2);
|
|
5953
|
+
var p1y=y1+fa*(y0-y2);
|
|
5914
5954
|
|
|
5915
|
-
|
|
5916
|
-
|
|
5955
|
+
var p2x=x1-fb*(x0-x2);
|
|
5956
|
+
var p2y=y1-fb*(y0-y2);
|
|
5917
5957
|
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
drawSpline( ctx, pts, t ) {
|
|
5958
|
+
return [p1x,p1y,p2x,p2y]
|
|
5959
|
+
}
|
|
5921
5960
|
|
|
5922
|
-
|
|
5923
|
-
var cp = []; // array of control points, as x0,y0,x1,y1,...
|
|
5924
|
-
var n = pts.length;
|
|
5961
|
+
LX.getControlPoints = getControlPoints;
|
|
5925
5962
|
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5963
|
+
/**
|
|
5964
|
+
* @method drawSpline
|
|
5965
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
5966
|
+
* @param {Array} pts
|
|
5967
|
+
* @param {Number} t
|
|
5968
|
+
**/
|
|
5969
|
+
function drawSpline( ctx, pts, t )
|
|
5970
|
+
{
|
|
5971
|
+
ctx.save();
|
|
5972
|
+
var cp = []; // array of control points, as x0,y0,x1,y1,...
|
|
5973
|
+
var n = pts.length;
|
|
5931
5974
|
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
ctx.stroke();
|
|
5938
|
-
ctx.closePath();
|
|
5939
|
-
}
|
|
5975
|
+
// Draw an open curve, not connected at the ends
|
|
5976
|
+
for( var i = 0; i < (n - 4); i += 2 )
|
|
5977
|
+
{
|
|
5978
|
+
cp = cp.concat(LX.getControlPoints(pts[ i ],pts[i+1],pts[i+2],pts[i+3],pts[i+4],pts[i+5],t));
|
|
5979
|
+
}
|
|
5940
5980
|
|
|
5941
|
-
|
|
5981
|
+
for( var i = 2; i < ( pts.length - 5 ); i += 2 )
|
|
5982
|
+
{
|
|
5942
5983
|
ctx.beginPath();
|
|
5943
|
-
ctx.moveTo(
|
|
5944
|
-
ctx.
|
|
5984
|
+
ctx.moveTo(pts[ i ], pts[i+1]);
|
|
5985
|
+
ctx.bezierCurveTo(cp[2*i-2],cp[2*i-1],cp[2*i],cp[2*i+1],pts[i+2],pts[i+3]);
|
|
5945
5986
|
ctx.stroke();
|
|
5946
5987
|
ctx.closePath();
|
|
5988
|
+
}
|
|
5947
5989
|
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5990
|
+
// For open curves the first and last arcs are simple quadratics.
|
|
5991
|
+
ctx.beginPath();
|
|
5992
|
+
ctx.moveTo( pts[ 0 ], pts[ 1 ] );
|
|
5993
|
+
ctx.quadraticCurveTo( cp[ 0 ], cp[ 1 ], pts[ 2 ], pts[ 3 ]);
|
|
5994
|
+
ctx.stroke();
|
|
5995
|
+
ctx.closePath();
|
|
5953
5996
|
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5997
|
+
ctx.beginPath();
|
|
5998
|
+
ctx.moveTo( pts[ n-2 ], pts[ n-1 ] );
|
|
5999
|
+
ctx.quadraticCurveTo( cp[ 2*n-10 ], cp[ 2*n-9 ], pts[ n-4 ], pts[ n-3 ]);
|
|
6000
|
+
ctx.stroke();
|
|
6001
|
+
ctx.closePath();
|
|
6002
|
+
|
|
6003
|
+
ctx.restore();
|
|
6004
|
+
}
|
|
5957
6005
|
|
|
6006
|
+
LX.drawSpline = drawSpline;
|
|
6007
|
+
|
|
5958
6008
|
// area.js @jxarco
|
|
5959
6009
|
|
|
5960
6010
|
class Area {
|
|
@@ -6678,7 +6728,7 @@ class Area {
|
|
|
6678
6728
|
|
|
6679
6729
|
addSidebar( callback, options = {} ) {
|
|
6680
6730
|
|
|
6681
|
-
let sidebar = new LX.Sidebar( options );
|
|
6731
|
+
let sidebar = new LX.Sidebar( { callback, ...options } );
|
|
6682
6732
|
|
|
6683
6733
|
if( callback )
|
|
6684
6734
|
{
|
|
@@ -7004,8 +7054,8 @@ class Area {
|
|
|
7004
7054
|
}
|
|
7005
7055
|
}
|
|
7006
7056
|
}
|
|
7007
|
-
LX.Area = Area;
|
|
7008
|
-
|
|
7057
|
+
LX.Area = Area;
|
|
7058
|
+
|
|
7009
7059
|
// widget.js @jxarco
|
|
7010
7060
|
|
|
7011
7061
|
/**
|
|
@@ -12175,8 +12225,8 @@ class Map2D extends Widget {
|
|
|
12175
12225
|
}
|
|
12176
12226
|
}
|
|
12177
12227
|
|
|
12178
|
-
LX.Map2D = Map2D;
|
|
12179
|
-
|
|
12228
|
+
LX.Map2D = Map2D;
|
|
12229
|
+
|
|
12180
12230
|
// panel.js @jxarco
|
|
12181
12231
|
|
|
12182
12232
|
/**
|
|
@@ -13356,8 +13406,8 @@ class Panel {
|
|
|
13356
13406
|
}
|
|
13357
13407
|
}
|
|
13358
13408
|
|
|
13359
|
-
LX.Panel = Panel;
|
|
13360
|
-
|
|
13409
|
+
LX.Panel = Panel;
|
|
13410
|
+
|
|
13361
13411
|
// branch.js @jxarco
|
|
13362
13412
|
|
|
13363
13413
|
/**
|
|
@@ -13581,8 +13631,8 @@ class Branch {
|
|
|
13581
13631
|
}
|
|
13582
13632
|
}
|
|
13583
13633
|
}
|
|
13584
|
-
LX.Branch = Branch;
|
|
13585
|
-
|
|
13634
|
+
LX.Branch = Branch;
|
|
13635
|
+
|
|
13586
13636
|
// menubar.js @jxarco
|
|
13587
13637
|
|
|
13588
13638
|
/**
|
|
@@ -13899,8 +13949,8 @@ class Menubar {
|
|
|
13899
13949
|
}
|
|
13900
13950
|
}
|
|
13901
13951
|
}
|
|
13902
|
-
LX.Menubar = Menubar;
|
|
13903
|
-
|
|
13952
|
+
LX.Menubar = Menubar;
|
|
13953
|
+
|
|
13904
13954
|
// sidebar.js @jxarco
|
|
13905
13955
|
|
|
13906
13956
|
/**
|
|
@@ -13936,6 +13986,7 @@ class Sidebar {
|
|
|
13936
13986
|
|
|
13937
13987
|
this.root = document.createElement( "div" );
|
|
13938
13988
|
this.root.className = "lexsidebar " + ( options.className ?? "" );
|
|
13989
|
+
this.callback = options.callback ?? null;
|
|
13939
13990
|
|
|
13940
13991
|
this._displaySelected = options.displaySelected ?? false;
|
|
13941
13992
|
|
|
@@ -13952,17 +14003,19 @@ class Sidebar {
|
|
|
13952
14003
|
configurable: true
|
|
13953
14004
|
});
|
|
13954
14005
|
|
|
14006
|
+
const mobile = navigator && /Android|iPhone/i.test( navigator.userAgent );
|
|
14007
|
+
|
|
13955
14008
|
this.side = options.side ?? "left";
|
|
13956
14009
|
this.collapsable = options.collapsable ?? true;
|
|
13957
14010
|
this._collapseWidth = ( options.collapseToIcons ?? true ) ? "58px" : "0px";
|
|
13958
|
-
this.collapsed =
|
|
14011
|
+
this.collapsed = options.collapsed ?? mobile;
|
|
13959
14012
|
|
|
13960
14013
|
this.filterString = "";
|
|
13961
14014
|
|
|
13962
14015
|
LX.doAsync( () => {
|
|
13963
14016
|
|
|
13964
14017
|
this.root.parentElement.ogWidth = this.root.parentElement.style.width;
|
|
13965
|
-
this.root.parentElement.style.transition = "width 0.25s ease-out";
|
|
14018
|
+
this.root.parentElement.style.transition = this.collapsed ? "" : "width 0.25s ease-out";
|
|
13966
14019
|
|
|
13967
14020
|
this.resizeObserver = new ResizeObserver( entries => {
|
|
13968
14021
|
for ( const entry of entries )
|
|
@@ -13971,6 +14024,24 @@ class Sidebar {
|
|
|
13971
14024
|
}
|
|
13972
14025
|
});
|
|
13973
14026
|
|
|
14027
|
+
if( this.collapsed )
|
|
14028
|
+
{
|
|
14029
|
+
this.root.classList.toggle( "collapsed", this.collapsed );
|
|
14030
|
+
this.root.parentElement.style.width = this._collapseWidth;
|
|
14031
|
+
|
|
14032
|
+
if( !this.resizeObserver )
|
|
14033
|
+
{
|
|
14034
|
+
throw( "Wait until ResizeObserver has been created!" );
|
|
14035
|
+
}
|
|
14036
|
+
|
|
14037
|
+
this.resizeObserver.observe( this.root.parentElement );
|
|
14038
|
+
|
|
14039
|
+
LX.doAsync( () => {
|
|
14040
|
+
this.resizeObserver.unobserve( this.root.parentElement );
|
|
14041
|
+
this.root.querySelectorAll( ".lexsidebarentrycontent" ).forEach( e => e.dataset[ "disableTooltip" ] = !this.collapsed );
|
|
14042
|
+
}, 10 );
|
|
14043
|
+
}
|
|
14044
|
+
|
|
13974
14045
|
}, 10 );
|
|
13975
14046
|
|
|
13976
14047
|
// Header
|
|
@@ -13986,11 +14057,29 @@ class Sidebar {
|
|
|
13986
14057
|
const icon = LX.makeIcon( this.side == "left" ? "PanelLeft" : "PanelRight", { title: "Toggle Sidebar", iconClass: "toggler" } );
|
|
13987
14058
|
this.header.appendChild( icon );
|
|
13988
14059
|
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
14060
|
+
if( mobile )
|
|
14061
|
+
{
|
|
14062
|
+
// create an area and append a sidebar:
|
|
14063
|
+
const area = new LX.Area({ skipAppend: true });
|
|
14064
|
+
const sheetSidebarOptions = LX.deepCopy( options );
|
|
14065
|
+
sheetSidebarOptions.collapsed = false;
|
|
14066
|
+
sheetSidebarOptions.collapsable = false;
|
|
14067
|
+
area.addSidebar( this.callback, sheetSidebarOptions );
|
|
14068
|
+
|
|
14069
|
+
icon.addEventListener( "click", e => {
|
|
14070
|
+
e.preventDefault();
|
|
14071
|
+
e.stopPropagation();
|
|
14072
|
+
new LX.Sheet("256px", [ area ], { side: this.side } );
|
|
14073
|
+
} );
|
|
14074
|
+
}
|
|
14075
|
+
else
|
|
14076
|
+
{
|
|
14077
|
+
icon.addEventListener( "click", e => {
|
|
14078
|
+
e.preventDefault();
|
|
14079
|
+
e.stopPropagation();
|
|
14080
|
+
this.toggleCollapsed();
|
|
14081
|
+
} );
|
|
14082
|
+
}
|
|
13994
14083
|
}
|
|
13995
14084
|
}
|
|
13996
14085
|
|
|
@@ -14547,8 +14636,8 @@ class Sidebar {
|
|
|
14547
14636
|
}
|
|
14548
14637
|
}
|
|
14549
14638
|
}
|
|
14550
|
-
LX.Sidebar = Sidebar;
|
|
14551
|
-
|
|
14639
|
+
LX.Sidebar = Sidebar;
|
|
14640
|
+
|
|
14552
14641
|
// asset_view.js @jxarco
|
|
14553
14642
|
|
|
14554
14643
|
class AssetViewEvent {
|
|
@@ -15415,6 +15504,6 @@ class AssetView {
|
|
|
15415
15504
|
}
|
|
15416
15505
|
}
|
|
15417
15506
|
|
|
15418
|
-
LX.AssetView = AssetView;
|
|
15419
|
-
|
|
15420
|
-
export { ADD_CUSTOM_WIDGET, Area, AssetView, AssetViewEvent, Branch, LX, Menubar, Panel, Sidebar, Widget };
|
|
15507
|
+
LX.AssetView = AssetView;
|
|
15508
|
+
|
|
15509
|
+
export { ADD_CUSTOM_WIDGET, Area, AssetView, AssetViewEvent, Branch, LX, Menubar, Panel, Sidebar, Widget };
|