lexgui 0.6.4 → 0.6.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/components/codeeditor.js +10 -10
- package/build/components/docmaker.js +417 -0
- package/build/components/nodegraph.js +12 -12
- package/build/components/timeline.js +170 -175
- package/build/lexgui-docs.css +410 -0
- package/build/lexgui.css +11 -0
- package/build/lexgui.js +1226 -1139
- package/build/lexgui.min.css +1 -1
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +1236 -1149
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +21 -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.6",
|
|
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;
|
|
@@ -1513,6 +1144,7 @@ class DropdownMenu {
|
|
|
1513
1144
|
{
|
|
1514
1145
|
const checkbox = new LX.Checkbox( pKey + "_entryChecked", item.checked, (v) => {
|
|
1515
1146
|
const f = item[ 'callback' ];
|
|
1147
|
+
item.checked = v;
|
|
1516
1148
|
if( f )
|
|
1517
1149
|
{
|
|
1518
1150
|
f.call( this, key, v, menuItem );
|
|
@@ -2247,13 +1879,6 @@ class Calendar {
|
|
|
2247
1879
|
|
|
2248
1880
|
LX.Calendar = Calendar;
|
|
2249
1881
|
|
|
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
1882
|
/**
|
|
2258
1883
|
* @class Tabs
|
|
2259
1884
|
*/
|
|
@@ -2379,7 +2004,7 @@ class Tabs {
|
|
|
2379
2004
|
this.thumb.style.transition = "none";
|
|
2380
2005
|
this.thumb.style.transform = "translate( " + ( tabEl.childIndex * tabEl.offsetWidth ) + "px )";
|
|
2381
2006
|
this.thumb.style.width = ( tabEl.offsetWidth ) + "px";
|
|
2382
|
-
flushCss( this.thumb );
|
|
2007
|
+
LX.flushCss( this.thumb );
|
|
2383
2008
|
this.thumb.style.transition = transition;
|
|
2384
2009
|
});
|
|
2385
2010
|
|
|
@@ -3493,7 +3118,7 @@ class CanvasCurve {
|
|
|
3493
3118
|
}
|
|
3494
3119
|
else
|
|
3495
3120
|
{
|
|
3496
|
-
LX.
|
|
3121
|
+
LX.drawSpline( ctx, values, element.smooth );
|
|
3497
3122
|
}
|
|
3498
3123
|
|
|
3499
3124
|
// Draw points
|
|
@@ -4435,254 +4060,6 @@ class CanvasMap2D {
|
|
|
4435
4060
|
|
|
4436
4061
|
LX.CanvasMap2D = CanvasMap2D;
|
|
4437
4062
|
|
|
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
4063
|
Object.defineProperty(String.prototype, 'lastChar', {
|
|
4687
4064
|
get: function() { return this[ this.length - 1 ]; },
|
|
4688
4065
|
enumerable: true,
|
|
@@ -4731,8 +4108,8 @@ Element.prototype.ignore = function( eventName, callbackName ) {
|
|
|
4731
4108
|
callbackName = callbackName ?? ( "_on" + eventName );
|
|
4732
4109
|
const callback = this[ callbackName ];
|
|
4733
4110
|
this.removeEventListener( eventName, callback );
|
|
4734
|
-
};
|
|
4735
|
-
|
|
4111
|
+
};
|
|
4112
|
+
|
|
4736
4113
|
// icons.js @jxarco
|
|
4737
4114
|
|
|
4738
4115
|
const RAW_ICONS = {
|
|
@@ -4910,8 +4287,8 @@ LX.LucideIconAlias = {
|
|
|
4910
4287
|
"RotateRight": "RotateCw",
|
|
4911
4288
|
"RotateBack": "RotateCcw",
|
|
4912
4289
|
"RotateLeft": "RotateCcw",
|
|
4913
|
-
};
|
|
4914
|
-
|
|
4290
|
+
};
|
|
4291
|
+
|
|
4915
4292
|
// utils.js @jxarco
|
|
4916
4293
|
|
|
4917
4294
|
function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
|
|
@@ -4960,15 +4337,39 @@ function doAsync( fn, ms ) {
|
|
|
4960
4337
|
LX.doAsync = doAsync;
|
|
4961
4338
|
|
|
4962
4339
|
/**
|
|
4963
|
-
* @method
|
|
4964
|
-
* @description
|
|
4965
|
-
*
|
|
4340
|
+
* @method flushCss
|
|
4341
|
+
* @description By reading the offsetHeight property, we are forcing the browser to flush
|
|
4342
|
+
* the pending CSS changes (which it does to ensure the value obtained is accurate).
|
|
4343
|
+
* @param {HTMLElement} element
|
|
4966
4344
|
*/
|
|
4967
|
-
function
|
|
4345
|
+
function flushCss( element )
|
|
4968
4346
|
{
|
|
4969
|
-
|
|
4347
|
+
element.offsetHeight;
|
|
4348
|
+
}
|
|
4970
4349
|
|
|
4971
|
-
|
|
4350
|
+
LX.flushCss = flushCss;
|
|
4351
|
+
|
|
4352
|
+
/**
|
|
4353
|
+
* @method deleteElement
|
|
4354
|
+
* @param {HTMLElement} element
|
|
4355
|
+
*/
|
|
4356
|
+
function deleteElement( element )
|
|
4357
|
+
{
|
|
4358
|
+
if( element !== undefined ) element.remove();
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4361
|
+
LX.deleteElement = deleteElement;
|
|
4362
|
+
|
|
4363
|
+
/**
|
|
4364
|
+
* @method getSupportedDOMName
|
|
4365
|
+
* @description Convert a text string to a valid DOM name
|
|
4366
|
+
* @param {String} text Original text
|
|
4367
|
+
*/
|
|
4368
|
+
function getSupportedDOMName( text )
|
|
4369
|
+
{
|
|
4370
|
+
console.assert( typeof text == "string", "getSupportedDOMName: Text is not a string!" );
|
|
4371
|
+
|
|
4372
|
+
let name = text.trim();
|
|
4972
4373
|
|
|
4973
4374
|
// Replace specific known symbols
|
|
4974
4375
|
name = name.replace( /@/g, '_at_' ).replace( /\+/g, '_plus_' ).replace( /\./g, '_dot_' );
|
|
@@ -5029,9 +4430,13 @@ LX.stripHTML = stripHTML;
|
|
|
5029
4430
|
* @param {Number|String} size
|
|
5030
4431
|
* @param {Number} total
|
|
5031
4432
|
*/
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
4433
|
+
function parsePixelSize( size, total )
|
|
4434
|
+
{
|
|
4435
|
+
// Assuming pixels..
|
|
4436
|
+
if( size.constructor === Number )
|
|
4437
|
+
{
|
|
4438
|
+
return size;
|
|
4439
|
+
}
|
|
5035
4440
|
|
|
5036
4441
|
if( size.constructor === String )
|
|
5037
4442
|
{
|
|
@@ -5069,7 +4474,7 @@ const parsePixelSize = ( size, total ) => {
|
|
|
5069
4474
|
}
|
|
5070
4475
|
|
|
5071
4476
|
throw( "Bad size format!" );
|
|
5072
|
-
}
|
|
4477
|
+
}
|
|
5073
4478
|
|
|
5074
4479
|
LX.parsePixelSize = parsePixelSize;
|
|
5075
4480
|
|
|
@@ -5332,7 +4737,7 @@ function measureRealWidth( value, paddingPlusMargin = 8 )
|
|
|
5332
4737
|
i.innerHTML = value;
|
|
5333
4738
|
document.body.appendChild( i );
|
|
5334
4739
|
var rect = i.getBoundingClientRect();
|
|
5335
|
-
LX.
|
|
4740
|
+
LX.deleteElement( i );
|
|
5336
4741
|
return rect.width + paddingPlusMargin;
|
|
5337
4742
|
}
|
|
5338
4743
|
|
|
@@ -5761,200 +5166,846 @@ function makeIcon( iconName, options = { } )
|
|
|
5761
5166
|
} );
|
|
5762
5167
|
}
|
|
5763
5168
|
|
|
5764
|
-
const path = document.createElement( "path" );
|
|
5765
|
-
path.setAttribute( "fill", "currentColor" );
|
|
5766
|
-
path.setAttribute( "d", data[ 4 ] );
|
|
5767
|
-
svg.appendChild( path );
|
|
5169
|
+
const path = document.createElement( "path" );
|
|
5170
|
+
path.setAttribute( "fill", "currentColor" );
|
|
5171
|
+
path.setAttribute( "d", data[ 4 ] );
|
|
5172
|
+
svg.appendChild( path );
|
|
5173
|
+
|
|
5174
|
+
if( data[ 5 ] )
|
|
5175
|
+
{
|
|
5176
|
+
const classes = data[ 5 ].pathClass;
|
|
5177
|
+
classes?.split( ' ' ).forEach( c => {
|
|
5178
|
+
path.classList.add( c );
|
|
5179
|
+
} );
|
|
5180
|
+
|
|
5181
|
+
const attrs = data[ 5 ].pathAttributes;
|
|
5182
|
+
attrs?.split( ' ' ).forEach( attr => {
|
|
5183
|
+
const t = attr.split( '=' );
|
|
5184
|
+
path.setAttribute( t[ 0 ], t[ 1 ] );
|
|
5185
|
+
} );
|
|
5186
|
+
}
|
|
5187
|
+
|
|
5188
|
+
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. -->`;
|
|
5189
|
+
svg.innerHTML += faLicense;
|
|
5190
|
+
return _createIconFromSVG( svg );
|
|
5191
|
+
}
|
|
5192
|
+
}
|
|
5193
|
+
|
|
5194
|
+
// Fallback to Lucide icon
|
|
5195
|
+
console.assert( lucideData, `No existing icon named _${ iconName }_` );
|
|
5196
|
+
svg = lucide.createElement( lucideData, options );
|
|
5197
|
+
|
|
5198
|
+
return _createIconFromSVG( svg );
|
|
5199
|
+
}
|
|
5200
|
+
|
|
5201
|
+
LX.makeIcon = makeIcon;
|
|
5202
|
+
|
|
5203
|
+
/**
|
|
5204
|
+
* @method registerIcon
|
|
5205
|
+
* @description Register an SVG icon to LX.ICONS
|
|
5206
|
+
* @param {String} iconName
|
|
5207
|
+
* @param {String} svgString
|
|
5208
|
+
* @param {String} variant
|
|
5209
|
+
* @param {Array} aliases
|
|
5210
|
+
*/
|
|
5211
|
+
function registerIcon( iconName, svgString, variant = "none", aliases = [] )
|
|
5212
|
+
{
|
|
5213
|
+
const svg = new DOMParser().parseFromString( svgString, 'image/svg+xml' ).documentElement;
|
|
5214
|
+
const path = svg.querySelector( "path" );
|
|
5215
|
+
const viewBox = svg.getAttribute( "viewBox" ).split( ' ' );
|
|
5216
|
+
const pathData = path.getAttribute( 'd' );
|
|
5217
|
+
|
|
5218
|
+
let svgAttributes = [];
|
|
5219
|
+
let pathAttributes = [];
|
|
5220
|
+
|
|
5221
|
+
for( const attr of svg.attributes )
|
|
5222
|
+
{
|
|
5223
|
+
switch( attr.name )
|
|
5224
|
+
{
|
|
5225
|
+
case "transform":
|
|
5226
|
+
case "fill":
|
|
5227
|
+
case "stroke-width":
|
|
5228
|
+
case "stroke-linecap":
|
|
5229
|
+
case "stroke-linejoin":
|
|
5230
|
+
svgAttributes.push( `${ attr.name }=${ attr.value }` );
|
|
5231
|
+
break;
|
|
5232
|
+
}
|
|
5233
|
+
}
|
|
5234
|
+
|
|
5235
|
+
for( const attr of path.attributes )
|
|
5236
|
+
{
|
|
5237
|
+
switch( attr.name )
|
|
5238
|
+
{
|
|
5239
|
+
case "transform":
|
|
5240
|
+
case "fill":
|
|
5241
|
+
case "stroke-width":
|
|
5242
|
+
case "stroke-linecap":
|
|
5243
|
+
case "stroke-linejoin":
|
|
5244
|
+
pathAttributes.push( `${ attr.name }=${ attr.value }` );
|
|
5245
|
+
break;
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
|
|
5249
|
+
const iconData = [
|
|
5250
|
+
parseInt( viewBox[ 2 ] ),
|
|
5251
|
+
parseInt( viewBox[ 3 ] ),
|
|
5252
|
+
aliases,
|
|
5253
|
+
variant,
|
|
5254
|
+
pathData,
|
|
5255
|
+
{
|
|
5256
|
+
svgAttributes: svgAttributes.length ? svgAttributes.join( ' ' ) : null,
|
|
5257
|
+
pathAttributes: pathAttributes.length ? pathAttributes.join( ' ' ) : null
|
|
5258
|
+
}
|
|
5259
|
+
];
|
|
5260
|
+
|
|
5261
|
+
if( LX.ICONS[ iconName ] )
|
|
5262
|
+
{
|
|
5263
|
+
console.warn( `${ iconName } will be added/replaced in LX.ICONS` );
|
|
5264
|
+
}
|
|
5265
|
+
|
|
5266
|
+
LX.ICONS[ iconName ] = iconData;
|
|
5267
|
+
}
|
|
5268
|
+
|
|
5269
|
+
LX.registerIcon = registerIcon;
|
|
5270
|
+
|
|
5271
|
+
/**
|
|
5272
|
+
* @method registerCommandbarEntry
|
|
5273
|
+
* @description Adds an extra command bar entry
|
|
5274
|
+
* @param {String} name
|
|
5275
|
+
* @param {Function} callback
|
|
5276
|
+
*/
|
|
5277
|
+
function registerCommandbarEntry( name, callback )
|
|
5278
|
+
{
|
|
5279
|
+
LX.extraCommandbarEntries.push( { name, callback } );
|
|
5280
|
+
}
|
|
5281
|
+
|
|
5282
|
+
LX.registerCommandbarEntry = registerCommandbarEntry;
|
|
5283
|
+
|
|
5284
|
+
/*
|
|
5285
|
+
Dialog and Notification Elements
|
|
5286
|
+
*/
|
|
5287
|
+
|
|
5288
|
+
/**
|
|
5289
|
+
* @method message
|
|
5290
|
+
* @param {String} text
|
|
5291
|
+
* @param {String} title (Optional)
|
|
5292
|
+
* @param {Object} options
|
|
5293
|
+
* id: Id of the message dialog
|
|
5294
|
+
* position: Dialog position in screen [screen centered]
|
|
5295
|
+
* draggable: Dialog can be dragged [false]
|
|
5296
|
+
*/
|
|
5297
|
+
|
|
5298
|
+
function message( text, title, options = {} )
|
|
5299
|
+
{
|
|
5300
|
+
if( !text )
|
|
5301
|
+
{
|
|
5302
|
+
throw( "No message to show" );
|
|
5303
|
+
}
|
|
5304
|
+
|
|
5305
|
+
options.modal = true;
|
|
5306
|
+
|
|
5307
|
+
return new LX.Dialog( title, p => {
|
|
5308
|
+
p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
|
|
5309
|
+
}, options );
|
|
5310
|
+
}
|
|
5311
|
+
|
|
5312
|
+
LX.message = message;
|
|
5313
|
+
|
|
5314
|
+
/**
|
|
5315
|
+
* @method popup
|
|
5316
|
+
* @param {String} text
|
|
5317
|
+
* @param {String} title (Optional)
|
|
5318
|
+
* @param {Object} options
|
|
5319
|
+
* id: Id of the message dialog
|
|
5320
|
+
* timeout (Number): Delay time before it closes automatically (ms). Default: [3000]
|
|
5321
|
+
* position (Array): [x,y] Dialog position in screen. Default: [screen centered]
|
|
5322
|
+
* size (Array): [width, height]
|
|
5323
|
+
*/
|
|
5324
|
+
|
|
5325
|
+
function popup( text, title, options = {} )
|
|
5326
|
+
{
|
|
5327
|
+
if( !text )
|
|
5328
|
+
{
|
|
5329
|
+
throw("No message to show");
|
|
5330
|
+
}
|
|
5331
|
+
|
|
5332
|
+
options.size = options.size ?? [ "max-content", "auto" ];
|
|
5333
|
+
options.class = "lexpopup";
|
|
5334
|
+
|
|
5335
|
+
const time = options.timeout || 3000;
|
|
5336
|
+
const dialog = new LX.Dialog( title, p => {
|
|
5337
|
+
p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
|
|
5338
|
+
}, options );
|
|
5339
|
+
|
|
5340
|
+
setTimeout( () => {
|
|
5341
|
+
dialog.close();
|
|
5342
|
+
}, Math.max( time, 150 ) );
|
|
5343
|
+
|
|
5344
|
+
return dialog;
|
|
5345
|
+
}
|
|
5346
|
+
|
|
5347
|
+
LX.popup = popup;
|
|
5348
|
+
|
|
5349
|
+
/**
|
|
5350
|
+
* @method prompt
|
|
5351
|
+
* @param {String} text
|
|
5352
|
+
* @param {String} title (Optional)
|
|
5353
|
+
* @param {Object} options
|
|
5354
|
+
* id: Id of the prompt dialog
|
|
5355
|
+
* position: Dialog position in screen [screen centered]
|
|
5356
|
+
* draggable: Dialog can be dragged [false]
|
|
5357
|
+
* input: If false, no text input appears
|
|
5358
|
+
* accept: Accept text
|
|
5359
|
+
* required: Input has to be filled [true]. Default: false
|
|
5360
|
+
*/
|
|
5361
|
+
|
|
5362
|
+
function prompt( text, title, callback, options = {} )
|
|
5363
|
+
{
|
|
5364
|
+
options.modal = true;
|
|
5365
|
+
options.className = "prompt";
|
|
5366
|
+
|
|
5367
|
+
let value = "";
|
|
5368
|
+
|
|
5369
|
+
const dialog = new LX.Dialog( title, p => {
|
|
5370
|
+
|
|
5371
|
+
p.addTextArea( null, text, null, { disabled: true, fitHeight: true } );
|
|
5372
|
+
|
|
5373
|
+
if( options.input ?? true )
|
|
5374
|
+
{
|
|
5375
|
+
p.addText( null, options.input || value, v => value = v, { placeholder: "..." } );
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5378
|
+
p.sameLine( 2 );
|
|
5379
|
+
|
|
5380
|
+
p.addButton(null, "Cancel", () => {if(options.on_cancel) options.on_cancel(); dialog.close();} );
|
|
5381
|
+
|
|
5382
|
+
p.addButton( null, options.accept || "Continue", () => {
|
|
5383
|
+
if( options.required && value === '' )
|
|
5384
|
+
{
|
|
5385
|
+
text += text.includes("You must fill the input text.") ? "": "\nYou must fill the input text.";
|
|
5386
|
+
dialog.close();
|
|
5387
|
+
prompt( text, title, callback, options );
|
|
5388
|
+
}
|
|
5389
|
+
else
|
|
5390
|
+
{
|
|
5391
|
+
if( callback ) callback.call( this, value );
|
|
5392
|
+
dialog.close();
|
|
5393
|
+
}
|
|
5394
|
+
}, { buttonClass: "primary" });
|
|
5395
|
+
|
|
5396
|
+
}, options );
|
|
5397
|
+
|
|
5398
|
+
// Focus text prompt
|
|
5399
|
+
if( options.input ?? true )
|
|
5400
|
+
{
|
|
5401
|
+
dialog.root.querySelector( 'input' ).focus();
|
|
5402
|
+
}
|
|
5403
|
+
|
|
5404
|
+
return dialog;
|
|
5405
|
+
}
|
|
5406
|
+
|
|
5407
|
+
LX.prompt = prompt;
|
|
5408
|
+
|
|
5409
|
+
/**
|
|
5410
|
+
* @method toast
|
|
5411
|
+
* @param {String} title
|
|
5412
|
+
* @param {String} description (Optional)
|
|
5413
|
+
* @param {Object} options
|
|
5414
|
+
* action: Data of the custom action { name, callback }
|
|
5415
|
+
* closable: Allow closing the toast
|
|
5416
|
+
* timeout: Time in which the toast closed automatically, in ms. -1 means persistent. [3000]
|
|
5417
|
+
*/
|
|
5418
|
+
|
|
5419
|
+
function toast( title, description, options = {} )
|
|
5420
|
+
{
|
|
5421
|
+
if( !title )
|
|
5422
|
+
{
|
|
5423
|
+
throw( "The toast needs at least a title!" );
|
|
5424
|
+
}
|
|
5425
|
+
|
|
5426
|
+
console.assert( this.notifications );
|
|
5427
|
+
|
|
5428
|
+
const toast = document.createElement( "li" );
|
|
5429
|
+
toast.className = "lextoast";
|
|
5430
|
+
toast.style.translate = "0 calc(100% + 30px)";
|
|
5431
|
+
this.notifications.prepend( toast );
|
|
5432
|
+
|
|
5433
|
+
LX.doAsync( () => {
|
|
5434
|
+
|
|
5435
|
+
if( this.notifications.offsetWidth > this.notifications.iWidth )
|
|
5436
|
+
{
|
|
5437
|
+
this.notifications.iWidth = Math.min( this.notifications.offsetWidth, 480 );
|
|
5438
|
+
this.notifications.style.width = this.notifications.iWidth + "px";
|
|
5439
|
+
}
|
|
5440
|
+
|
|
5441
|
+
toast.dataset[ "open" ] = true;
|
|
5442
|
+
}, 10 );
|
|
5443
|
+
|
|
5444
|
+
const content = document.createElement( "div" );
|
|
5445
|
+
content.className = "lextoastcontent";
|
|
5446
|
+
toast.appendChild( content );
|
|
5447
|
+
|
|
5448
|
+
const titleContent = document.createElement( "div" );
|
|
5449
|
+
titleContent.className = "title";
|
|
5450
|
+
titleContent.innerHTML = title;
|
|
5451
|
+
content.appendChild( titleContent );
|
|
5452
|
+
|
|
5453
|
+
if( description )
|
|
5454
|
+
{
|
|
5455
|
+
const desc = document.createElement( "div" );
|
|
5456
|
+
desc.className = "desc";
|
|
5457
|
+
desc.innerHTML = description;
|
|
5458
|
+
content.appendChild( desc );
|
|
5459
|
+
}
|
|
5460
|
+
|
|
5461
|
+
if( options.action )
|
|
5462
|
+
{
|
|
5463
|
+
const panel = new LX.Panel();
|
|
5464
|
+
panel.addButton(null, options.action.name ?? "Accept", options.action.callback.bind( this, toast ), { width: "auto", maxWidth: "150px", className: "right", buttonClass: "border" });
|
|
5465
|
+
toast.appendChild( panel.root.childNodes[ 0 ] );
|
|
5466
|
+
}
|
|
5467
|
+
|
|
5468
|
+
const that = this;
|
|
5469
|
+
|
|
5470
|
+
toast.close = function() {
|
|
5471
|
+
this.dataset[ "closed" ] = true;
|
|
5472
|
+
LX.doAsync( () => {
|
|
5473
|
+
this.remove();
|
|
5474
|
+
if( !that.notifications.childElementCount )
|
|
5475
|
+
{
|
|
5476
|
+
that.notifications.style.width = "unset";
|
|
5477
|
+
that.notifications.iWidth = 0;
|
|
5478
|
+
}
|
|
5479
|
+
}, 500 );
|
|
5480
|
+
};
|
|
5481
|
+
|
|
5482
|
+
if( options.closable ?? true )
|
|
5483
|
+
{
|
|
5484
|
+
const closeIcon = LX.makeIcon( "X", { iconClass: "closer" } );
|
|
5485
|
+
closeIcon.addEventListener( "click", () => {
|
|
5486
|
+
toast.close();
|
|
5487
|
+
} );
|
|
5488
|
+
toast.appendChild( closeIcon );
|
|
5489
|
+
}
|
|
5490
|
+
|
|
5491
|
+
const timeout = options.timeout ?? 3000;
|
|
5492
|
+
|
|
5493
|
+
if( timeout != -1 )
|
|
5494
|
+
{
|
|
5495
|
+
LX.doAsync( () => {
|
|
5496
|
+
toast.close();
|
|
5497
|
+
}, timeout );
|
|
5498
|
+
}
|
|
5499
|
+
}
|
|
5500
|
+
|
|
5501
|
+
LX.toast = toast;
|
|
5502
|
+
|
|
5503
|
+
/**
|
|
5504
|
+
* @method badge
|
|
5505
|
+
* @param {String} text
|
|
5506
|
+
* @param {String} className
|
|
5507
|
+
* @param {Object} options
|
|
5508
|
+
* style: Style attributes to override
|
|
5509
|
+
* asElement: Returns the badge as HTMLElement [false]
|
|
5510
|
+
*/
|
|
5511
|
+
|
|
5512
|
+
function badge( text, className, options = {} )
|
|
5513
|
+
{
|
|
5514
|
+
const container = document.createElement( "div" );
|
|
5515
|
+
container.innerHTML = text;
|
|
5516
|
+
container.className = "lexbadge " + ( className ?? "" );
|
|
5517
|
+
Object.assign( container.style, options.style ?? {} );
|
|
5518
|
+
return ( options.asElement ?? false ) ? container : container.outerHTML;
|
|
5519
|
+
}
|
|
5520
|
+
|
|
5521
|
+
LX.badge = badge;
|
|
5522
|
+
|
|
5523
|
+
/**
|
|
5524
|
+
* @method makeElement
|
|
5525
|
+
* @param {String} htmlType
|
|
5526
|
+
* @param {String} className
|
|
5527
|
+
* @param {String} innerHTML
|
|
5528
|
+
* @param {HTMLElement} parent
|
|
5529
|
+
* @param {Object} overrideStyle
|
|
5530
|
+
*/
|
|
5531
|
+
|
|
5532
|
+
function makeElement( htmlType, className, innerHTML, parent, overrideStyle = {} )
|
|
5533
|
+
{
|
|
5534
|
+
const element = document.createElement( htmlType );
|
|
5535
|
+
element.className = className ?? "";
|
|
5536
|
+
element.innerHTML = innerHTML ?? "";
|
|
5537
|
+
Object.assign( element.style, overrideStyle );
|
|
5538
|
+
|
|
5539
|
+
if( parent )
|
|
5540
|
+
{
|
|
5541
|
+
if( parent.attach ) // Use attach method if possible
|
|
5542
|
+
{
|
|
5543
|
+
parent.attach( element );
|
|
5544
|
+
}
|
|
5545
|
+
else // its a native HTMLElement
|
|
5546
|
+
{
|
|
5547
|
+
parent.appendChild( element );
|
|
5548
|
+
}
|
|
5549
|
+
}
|
|
5550
|
+
|
|
5551
|
+
return element;
|
|
5552
|
+
}
|
|
5553
|
+
|
|
5554
|
+
LX.makeElement = makeElement;
|
|
5555
|
+
|
|
5556
|
+
/**
|
|
5557
|
+
* @method makeContainer
|
|
5558
|
+
* @param {Array} size
|
|
5559
|
+
* @param {String} className
|
|
5560
|
+
* @param {String} innerHTML
|
|
5561
|
+
* @param {HTMLElement} parent
|
|
5562
|
+
* @param {Object} overrideStyle
|
|
5563
|
+
*/
|
|
5564
|
+
|
|
5565
|
+
function makeContainer( size, className, innerHTML, parent, overrideStyle = {} )
|
|
5566
|
+
{
|
|
5567
|
+
const container = LX.makeElement( "div", "lexcontainer " + ( className ?? "" ), innerHTML, parent, overrideStyle );
|
|
5568
|
+
container.style.width = size && size[ 0 ] ? size[ 0 ] : "100%";
|
|
5569
|
+
container.style.height = size && size[ 1 ] ? size[ 1 ] : "100%";
|
|
5570
|
+
return container;
|
|
5571
|
+
}
|
|
5572
|
+
|
|
5573
|
+
LX.makeContainer = makeContainer;
|
|
5574
|
+
|
|
5575
|
+
/**
|
|
5576
|
+
* @method asTooltip
|
|
5577
|
+
* @param {HTMLElement} trigger
|
|
5578
|
+
* @param {String} content
|
|
5579
|
+
* @param {Object} options
|
|
5580
|
+
* side: Side of the tooltip
|
|
5581
|
+
* offset: Tooltip margin offset
|
|
5582
|
+
* active: Tooltip active by default [true]
|
|
5583
|
+
*/
|
|
5584
|
+
|
|
5585
|
+
function asTooltip( trigger, content, options = {} )
|
|
5586
|
+
{
|
|
5587
|
+
console.assert( trigger, "You need a trigger to generate a tooltip!" );
|
|
5588
|
+
|
|
5589
|
+
trigger.dataset[ "disableTooltip" ] = !( options.active ?? true );
|
|
5590
|
+
|
|
5591
|
+
let tooltipDom = null;
|
|
5592
|
+
|
|
5593
|
+
trigger.addEventListener( "mouseenter", function(e) {
|
|
5594
|
+
|
|
5595
|
+
if( trigger.dataset[ "disableTooltip" ] == "true" )
|
|
5596
|
+
{
|
|
5597
|
+
return;
|
|
5598
|
+
}
|
|
5599
|
+
|
|
5600
|
+
LX.root.querySelectorAll( ".lextooltip" ).forEach( e => e.remove() );
|
|
5601
|
+
|
|
5602
|
+
tooltipDom = document.createElement( "div" );
|
|
5603
|
+
tooltipDom.className = "lextooltip";
|
|
5604
|
+
tooltipDom.innerHTML = content;
|
|
5605
|
+
|
|
5606
|
+
LX.doAsync( () => {
|
|
5607
|
+
|
|
5608
|
+
const position = [ 0, 0 ];
|
|
5609
|
+
const rect = this.getBoundingClientRect();
|
|
5610
|
+
const offset = options.offset ?? 6;
|
|
5611
|
+
let alignWidth = true;
|
|
5612
|
+
|
|
5613
|
+
switch( options.side ?? "top" )
|
|
5614
|
+
{
|
|
5615
|
+
case "left":
|
|
5616
|
+
position[ 0 ] += ( rect.x - tooltipDom.offsetWidth - offset );
|
|
5617
|
+
alignWidth = false;
|
|
5618
|
+
break;
|
|
5619
|
+
case "right":
|
|
5620
|
+
position[ 0 ] += ( rect.x + rect.width + offset );
|
|
5621
|
+
alignWidth = false;
|
|
5622
|
+
break;
|
|
5623
|
+
case "top":
|
|
5624
|
+
position[ 1 ] += ( rect.y - tooltipDom.offsetHeight - offset );
|
|
5625
|
+
alignWidth = true;
|
|
5626
|
+
break;
|
|
5627
|
+
case "bottom":
|
|
5628
|
+
position[ 1 ] += ( rect.y + rect.height + offset );
|
|
5629
|
+
alignWidth = true;
|
|
5630
|
+
break;
|
|
5631
|
+
}
|
|
5632
|
+
|
|
5633
|
+
if( alignWidth ) { position[ 0 ] += ( rect.x + rect.width * 0.5 ) - tooltipDom.offsetWidth * 0.5; }
|
|
5634
|
+
else { position[ 1 ] += ( rect.y + rect.height * 0.5 ) - tooltipDom.offsetHeight * 0.5; }
|
|
5635
|
+
|
|
5636
|
+
// Avoid collisions
|
|
5637
|
+
position[ 0 ] = LX.clamp( position[ 0 ], 0, window.innerWidth - tooltipDom.offsetWidth - 4 );
|
|
5638
|
+
position[ 1 ] = LX.clamp( position[ 1 ], 0, window.innerHeight - tooltipDom.offsetHeight - 4 );
|
|
5639
|
+
|
|
5640
|
+
tooltipDom.style.left = `${ position[ 0 ] }px`;
|
|
5641
|
+
tooltipDom.style.top = `${ position[ 1 ] }px`;
|
|
5642
|
+
} );
|
|
5643
|
+
|
|
5644
|
+
LX.root.appendChild( tooltipDom );
|
|
5645
|
+
} );
|
|
5646
|
+
|
|
5647
|
+
trigger.addEventListener( "mouseleave", function(e) {
|
|
5648
|
+
if( tooltipDom )
|
|
5649
|
+
{
|
|
5650
|
+
tooltipDom.remove();
|
|
5651
|
+
}
|
|
5652
|
+
} );
|
|
5653
|
+
}
|
|
5654
|
+
|
|
5655
|
+
LX.asTooltip = asTooltip;
|
|
5656
|
+
|
|
5657
|
+
/*
|
|
5658
|
+
* Requests
|
|
5659
|
+
*/
|
|
5660
|
+
|
|
5661
|
+
Object.assign(LX, {
|
|
5662
|
+
|
|
5663
|
+
/**
|
|
5664
|
+
* Request file from url (it could be a binary, text, etc.). If you want a simplied version use
|
|
5665
|
+
* @method request
|
|
5666
|
+
* @param {Object} request object with all the parameters like data (for sending forms), dataType, success, error
|
|
5667
|
+
* @param {Function} on_complete
|
|
5668
|
+
**/
|
|
5669
|
+
request( request ) {
|
|
5670
|
+
|
|
5671
|
+
var dataType = request.dataType || "text";
|
|
5672
|
+
if(dataType == "json") //parse it locally
|
|
5673
|
+
dataType = "text";
|
|
5674
|
+
else if(dataType == "xml") //parse it locally
|
|
5675
|
+
dataType = "text";
|
|
5676
|
+
else if (dataType == "binary")
|
|
5677
|
+
{
|
|
5678
|
+
//request.mimeType = "text/plain; charset=x-user-defined";
|
|
5679
|
+
dataType = "arraybuffer";
|
|
5680
|
+
request.mimeType = "application/octet-stream";
|
|
5681
|
+
}
|
|
5682
|
+
|
|
5683
|
+
//regular case, use AJAX call
|
|
5684
|
+
var xhr = new XMLHttpRequest();
|
|
5685
|
+
xhr.open( request.data ? 'POST' : 'GET', request.url, true);
|
|
5686
|
+
if(dataType)
|
|
5687
|
+
xhr.responseType = dataType;
|
|
5688
|
+
if (request.mimeType)
|
|
5689
|
+
xhr.overrideMimeType( request.mimeType );
|
|
5690
|
+
if( request.nocache )
|
|
5691
|
+
xhr.setRequestHeader('Cache-Control', 'no-cache');
|
|
5692
|
+
|
|
5693
|
+
xhr.onload = function(load)
|
|
5694
|
+
{
|
|
5695
|
+
var response = this.response;
|
|
5696
|
+
if( this.status != 200)
|
|
5697
|
+
{
|
|
5698
|
+
var err = "Error " + this.status;
|
|
5699
|
+
if(request.error)
|
|
5700
|
+
request.error(err);
|
|
5701
|
+
return;
|
|
5702
|
+
}
|
|
5703
|
+
|
|
5704
|
+
if(request.dataType == "json") //chrome doesnt support json format
|
|
5705
|
+
{
|
|
5706
|
+
try
|
|
5707
|
+
{
|
|
5708
|
+
response = JSON.parse(response);
|
|
5709
|
+
}
|
|
5710
|
+
catch (err)
|
|
5711
|
+
{
|
|
5712
|
+
if(request.error)
|
|
5713
|
+
request.error(err);
|
|
5714
|
+
else
|
|
5715
|
+
throw err;
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5718
|
+
else if(request.dataType == "xml")
|
|
5719
|
+
{
|
|
5720
|
+
try
|
|
5721
|
+
{
|
|
5722
|
+
var xmlparser = new DOMParser();
|
|
5723
|
+
response = xmlparser.parseFromString(response,"text/xml");
|
|
5724
|
+
}
|
|
5725
|
+
catch (err)
|
|
5726
|
+
{
|
|
5727
|
+
if(request.error)
|
|
5728
|
+
request.error(err);
|
|
5729
|
+
else
|
|
5730
|
+
throw err;
|
|
5731
|
+
}
|
|
5732
|
+
}
|
|
5733
|
+
if(request.success)
|
|
5734
|
+
request.success.call(this, response, this);
|
|
5735
|
+
};
|
|
5736
|
+
xhr.onerror = function(err) {
|
|
5737
|
+
if(request.error)
|
|
5738
|
+
request.error(err);
|
|
5739
|
+
};
|
|
5740
|
+
|
|
5741
|
+
var data = new FormData();
|
|
5742
|
+
if( request.data )
|
|
5743
|
+
{
|
|
5744
|
+
for( var i in request.data)
|
|
5745
|
+
data.append(i,request.data[ i ]);
|
|
5746
|
+
}
|
|
5747
|
+
|
|
5748
|
+
xhr.send( data );
|
|
5749
|
+
return xhr;
|
|
5750
|
+
},
|
|
5751
|
+
|
|
5752
|
+
/**
|
|
5753
|
+
* Request file from url
|
|
5754
|
+
* @method requestText
|
|
5755
|
+
* @param {String} url
|
|
5756
|
+
* @param {Function} onComplete
|
|
5757
|
+
* @param {Function} onError
|
|
5758
|
+
**/
|
|
5759
|
+
requestText( url, onComplete, onError ) {
|
|
5760
|
+
return this.request({ url: url, dataType:"text", success: onComplete, error: onError });
|
|
5761
|
+
},
|
|
5762
|
+
|
|
5763
|
+
/**
|
|
5764
|
+
* Request file from url
|
|
5765
|
+
* @method requestJSON
|
|
5766
|
+
* @param {String} url
|
|
5767
|
+
* @param {Function} onComplete
|
|
5768
|
+
* @param {Function} onError
|
|
5769
|
+
**/
|
|
5770
|
+
requestJSON( url, onComplete, onError ) {
|
|
5771
|
+
return this.request({ url: url, dataType:"json", success: onComplete, error: onError });
|
|
5772
|
+
},
|
|
5773
|
+
|
|
5774
|
+
/**
|
|
5775
|
+
* Request binary file from url
|
|
5776
|
+
* @method requestBinary
|
|
5777
|
+
* @param {String} url
|
|
5778
|
+
* @param {Function} onComplete
|
|
5779
|
+
* @param {Function} onError
|
|
5780
|
+
**/
|
|
5781
|
+
requestBinary( url, onComplete, onError ) {
|
|
5782
|
+
return this.request({ url: url, dataType:"binary", success: onComplete, error: onError });
|
|
5783
|
+
},
|
|
5784
|
+
|
|
5785
|
+
/**
|
|
5786
|
+
* Request script and inserts it in the DOM
|
|
5787
|
+
* @method requireScript
|
|
5788
|
+
* @param {String|Array} url the url of the script or an array containing several urls
|
|
5789
|
+
* @param {Function} onComplete
|
|
5790
|
+
* @param {Function} onError
|
|
5791
|
+
* @param {Function} onProgress (if several files are required, onProgress is called after every file is added to the DOM)
|
|
5792
|
+
**/
|
|
5793
|
+
requireScript( url, onComplete, onError, onProgress, version ) {
|
|
5768
5794
|
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
const classes = data[ 5 ].pathClass;
|
|
5772
|
-
classes?.split( ' ' ).forEach( c => {
|
|
5773
|
-
path.classList.add( c );
|
|
5774
|
-
} );
|
|
5795
|
+
if(!url)
|
|
5796
|
+
throw("invalid URL");
|
|
5775
5797
|
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
const t = attr.split( '=' );
|
|
5779
|
-
path.setAttribute( t[ 0 ], t[ 1 ] );
|
|
5780
|
-
} );
|
|
5781
|
-
}
|
|
5798
|
+
if( url.constructor === String )
|
|
5799
|
+
url = [url];
|
|
5782
5800
|
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
return _createIconFromSVG( svg );
|
|
5786
|
-
}
|
|
5787
|
-
}
|
|
5801
|
+
var total = url.length;
|
|
5802
|
+
var loaded_scripts = [];
|
|
5788
5803
|
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5804
|
+
for( var i in url)
|
|
5805
|
+
{
|
|
5806
|
+
var script = document.createElement('script');
|
|
5807
|
+
script.num = i;
|
|
5808
|
+
script.type = 'text/javascript';
|
|
5809
|
+
script.src = url[ i ] + ( version ? "?version=" + version : "" );
|
|
5810
|
+
script.original_src = url[ i ];
|
|
5811
|
+
script.async = false;
|
|
5812
|
+
script.onload = function( e ) {
|
|
5813
|
+
total--;
|
|
5814
|
+
loaded_scripts.push(this);
|
|
5815
|
+
if(total)
|
|
5816
|
+
{
|
|
5817
|
+
if( onProgress )
|
|
5818
|
+
{
|
|
5819
|
+
onProgress( this.original_src, this.num );
|
|
5820
|
+
}
|
|
5821
|
+
}
|
|
5822
|
+
else if(onComplete)
|
|
5823
|
+
onComplete( loaded_scripts );
|
|
5824
|
+
};
|
|
5825
|
+
if(onError)
|
|
5826
|
+
script.onerror = function(err) {
|
|
5827
|
+
onError(err, this.original_src, this.num );
|
|
5828
|
+
};
|
|
5829
|
+
document.getElementsByTagName('head')[ 0 ].appendChild(script);
|
|
5830
|
+
}
|
|
5831
|
+
},
|
|
5792
5832
|
|
|
5793
|
-
|
|
5794
|
-
|
|
5833
|
+
loadScriptSync( url ) {
|
|
5834
|
+
return new Promise((resolve, reject) => {
|
|
5835
|
+
const script = document.createElement( "script" );
|
|
5836
|
+
script.src = url;
|
|
5837
|
+
script.async = false;
|
|
5838
|
+
script.onload = () => resolve();
|
|
5839
|
+
script.onerror = () => reject(new Error(`Failed to load ${url}`));
|
|
5840
|
+
document.head.appendChild( script );
|
|
5841
|
+
});
|
|
5842
|
+
},
|
|
5795
5843
|
|
|
5796
|
-
|
|
5844
|
+
downloadURL( url, filename ) {
|
|
5797
5845
|
|
|
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' );
|
|
5846
|
+
const fr = new FileReader();
|
|
5812
5847
|
|
|
5813
|
-
|
|
5814
|
-
|
|
5848
|
+
const _download = function(_url) {
|
|
5849
|
+
var link = document.createElement('a');
|
|
5850
|
+
link.href = _url;
|
|
5851
|
+
link.download = filename;
|
|
5852
|
+
document.body.appendChild(link);
|
|
5853
|
+
link.click();
|
|
5854
|
+
document.body.removeChild(link);
|
|
5855
|
+
};
|
|
5815
5856
|
|
|
5816
|
-
|
|
5817
|
-
{
|
|
5818
|
-
switch( attr.name )
|
|
5857
|
+
if( url.includes('http') )
|
|
5819
5858
|
{
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5859
|
+
LX.request({ url: url, dataType: 'blob', success: (f) => {
|
|
5860
|
+
fr.readAsDataURL( f );
|
|
5861
|
+
fr.onload = e => {
|
|
5862
|
+
_download(e.currentTarget.result);
|
|
5863
|
+
};
|
|
5864
|
+
} });
|
|
5865
|
+
}else
|
|
5866
|
+
{
|
|
5867
|
+
_download(url);
|
|
5827
5868
|
}
|
|
5828
|
-
}
|
|
5829
5869
|
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5870
|
+
},
|
|
5871
|
+
|
|
5872
|
+
downloadFile: function( filename, data, dataType ) {
|
|
5873
|
+
if(!data)
|
|
5833
5874
|
{
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
case "stroke-width":
|
|
5837
|
-
case "stroke-linecap":
|
|
5838
|
-
case "stroke-linejoin":
|
|
5839
|
-
pathAttributes.push( `${ attr.name }=${ attr.value }` );
|
|
5840
|
-
break;
|
|
5875
|
+
console.warn("No file provided to download");
|
|
5876
|
+
return;
|
|
5841
5877
|
}
|
|
5842
|
-
}
|
|
5843
5878
|
|
|
5844
|
-
|
|
5845
|
-
parseInt( viewBox[ 2 ] ),
|
|
5846
|
-
parseInt( viewBox[ 3 ] ),
|
|
5847
|
-
aliases,
|
|
5848
|
-
variant,
|
|
5849
|
-
pathData,
|
|
5879
|
+
if(!dataType)
|
|
5850
5880
|
{
|
|
5851
|
-
|
|
5852
|
-
|
|
5881
|
+
if(data.constructor === String )
|
|
5882
|
+
dataType = 'text/plain';
|
|
5883
|
+
else
|
|
5884
|
+
dataType = 'application/octet-stream';
|
|
5853
5885
|
}
|
|
5854
|
-
];
|
|
5855
5886
|
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5887
|
+
var file = null;
|
|
5888
|
+
if(data.constructor !== File && data.constructor !== Blob)
|
|
5889
|
+
file = new Blob( [ data ], {type : dataType});
|
|
5890
|
+
else
|
|
5891
|
+
file = data;
|
|
5892
|
+
|
|
5893
|
+
var url = URL.createObjectURL( file );
|
|
5894
|
+
var element = document.createElement("a");
|
|
5895
|
+
element.setAttribute('href', url);
|
|
5896
|
+
element.setAttribute('download', filename );
|
|
5897
|
+
element.style.display = 'none';
|
|
5898
|
+
document.body.appendChild(element);
|
|
5899
|
+
element.click();
|
|
5900
|
+
document.body.removeChild(element);
|
|
5901
|
+
setTimeout( function(){ URL.revokeObjectURL( url ); }, 1000*60 ); //wait one minute to revoke url
|
|
5859
5902
|
}
|
|
5903
|
+
});
|
|
5860
5904
|
|
|
5861
|
-
|
|
5905
|
+
/**
|
|
5906
|
+
* @method compareThreshold
|
|
5907
|
+
* @param {String} url
|
|
5908
|
+
* @param {Function} onComplete
|
|
5909
|
+
* @param {Function} onError
|
|
5910
|
+
**/
|
|
5911
|
+
function compareThreshold( v, p, n, t )
|
|
5912
|
+
{
|
|
5913
|
+
return Math.abs( v - p ) >= t || Math.abs( v - n ) >= t;
|
|
5862
5914
|
}
|
|
5863
5915
|
|
|
5864
|
-
LX.
|
|
5916
|
+
LX.compareThreshold = compareThreshold;
|
|
5865
5917
|
|
|
5866
5918
|
/**
|
|
5867
|
-
* @method
|
|
5868
|
-
* @
|
|
5869
|
-
* @param {
|
|
5870
|
-
* @param {Function}
|
|
5871
|
-
|
|
5872
|
-
function
|
|
5919
|
+
* @method compareThresholdRange
|
|
5920
|
+
* @param {String} url
|
|
5921
|
+
* @param {Function} onComplete
|
|
5922
|
+
* @param {Function} onError
|
|
5923
|
+
**/
|
|
5924
|
+
function compareThresholdRange( v0, v1, t0, t1 )
|
|
5873
5925
|
{
|
|
5874
|
-
|
|
5926
|
+
return v0 >= t0 && v0 <= t1 || v1 >= t0 && v1 <= t1 || v0 <= t0 && v1 >= t1;
|
|
5875
5927
|
}
|
|
5876
5928
|
|
|
5877
|
-
LX.
|
|
5929
|
+
LX.compareThresholdRange = compareThresholdRange;
|
|
5878
5930
|
|
|
5879
5931
|
/**
|
|
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.
|
|
5932
|
+
* @method getControlPoints
|
|
5933
|
+
* @param {String} url
|
|
5934
|
+
* @param {Function} onComplete
|
|
5935
|
+
* @param {Function} onError
|
|
5936
|
+
**/
|
|
5937
|
+
function getControlPoints( x0, y0, x1, y1, x2, y2, t )
|
|
5938
|
+
{
|
|
5939
|
+
// x0,y0,x1,y1 are the coordinates of the end (knot) pts of this segment
|
|
5940
|
+
// x2,y2 is the next knot -- not connected here but needed to calculate p2
|
|
5941
|
+
// p1 is the control point calculated here, from x1 back toward x0.
|
|
5942
|
+
// p2 is the next control point, calculated here and returned to become the
|
|
5943
|
+
// next segment's p1.
|
|
5944
|
+
// t is the 'tension' which controls how far the control points spread.
|
|
5904
5945
|
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5946
|
+
// Scaling factors: distances from this knot to the previous and following knots.
|
|
5947
|
+
var d01=Math.sqrt(Math.pow(x1-x0,2)+Math.pow(y1-y0,2));
|
|
5948
|
+
var d12=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
|
|
5908
5949
|
|
|
5909
|
-
|
|
5910
|
-
|
|
5950
|
+
var fa=t*d01/(d01+d12);
|
|
5951
|
+
var fb=t-fa;
|
|
5911
5952
|
|
|
5912
|
-
|
|
5913
|
-
|
|
5953
|
+
var p1x=x1+fa*(x0-x2);
|
|
5954
|
+
var p1y=y1+fa*(y0-y2);
|
|
5914
5955
|
|
|
5915
|
-
|
|
5916
|
-
|
|
5956
|
+
var p2x=x1-fb*(x0-x2);
|
|
5957
|
+
var p2y=y1-fb*(y0-y2);
|
|
5917
5958
|
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
drawSpline( ctx, pts, t ) {
|
|
5959
|
+
return [p1x,p1y,p2x,p2y]
|
|
5960
|
+
}
|
|
5921
5961
|
|
|
5922
|
-
|
|
5923
|
-
var cp = []; // array of control points, as x0,y0,x1,y1,...
|
|
5924
|
-
var n = pts.length;
|
|
5962
|
+
LX.getControlPoints = getControlPoints;
|
|
5925
5963
|
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5964
|
+
/**
|
|
5965
|
+
* @method drawSpline
|
|
5966
|
+
* @param {CanvasRenderingContext2D} ctx
|
|
5967
|
+
* @param {Array} pts
|
|
5968
|
+
* @param {Number} t
|
|
5969
|
+
**/
|
|
5970
|
+
function drawSpline( ctx, pts, t )
|
|
5971
|
+
{
|
|
5972
|
+
ctx.save();
|
|
5973
|
+
var cp = []; // array of control points, as x0,y0,x1,y1,...
|
|
5974
|
+
var n = pts.length;
|
|
5931
5975
|
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
ctx.stroke();
|
|
5938
|
-
ctx.closePath();
|
|
5939
|
-
}
|
|
5976
|
+
// Draw an open curve, not connected at the ends
|
|
5977
|
+
for( var i = 0; i < (n - 4); i += 2 )
|
|
5978
|
+
{
|
|
5979
|
+
cp = cp.concat(LX.getControlPoints(pts[ i ],pts[i+1],pts[i+2],pts[i+3],pts[i+4],pts[i+5],t));
|
|
5980
|
+
}
|
|
5940
5981
|
|
|
5941
|
-
|
|
5982
|
+
for( var i = 2; i < ( pts.length - 5 ); i += 2 )
|
|
5983
|
+
{
|
|
5942
5984
|
ctx.beginPath();
|
|
5943
|
-
ctx.moveTo(
|
|
5944
|
-
ctx.
|
|
5985
|
+
ctx.moveTo(pts[ i ], pts[i+1]);
|
|
5986
|
+
ctx.bezierCurveTo(cp[2*i-2],cp[2*i-1],cp[2*i],cp[2*i+1],pts[i+2],pts[i+3]);
|
|
5945
5987
|
ctx.stroke();
|
|
5946
5988
|
ctx.closePath();
|
|
5989
|
+
}
|
|
5947
5990
|
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5991
|
+
// For open curves the first and last arcs are simple quadratics.
|
|
5992
|
+
ctx.beginPath();
|
|
5993
|
+
ctx.moveTo( pts[ 0 ], pts[ 1 ] );
|
|
5994
|
+
ctx.quadraticCurveTo( cp[ 0 ], cp[ 1 ], pts[ 2 ], pts[ 3 ]);
|
|
5995
|
+
ctx.stroke();
|
|
5996
|
+
ctx.closePath();
|
|
5953
5997
|
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5998
|
+
ctx.beginPath();
|
|
5999
|
+
ctx.moveTo( pts[ n-2 ], pts[ n-1 ] );
|
|
6000
|
+
ctx.quadraticCurveTo( cp[ 2*n-10 ], cp[ 2*n-9 ], pts[ n-4 ], pts[ n-3 ]);
|
|
6001
|
+
ctx.stroke();
|
|
6002
|
+
ctx.closePath();
|
|
6003
|
+
|
|
6004
|
+
ctx.restore();
|
|
6005
|
+
}
|
|
5957
6006
|
|
|
6007
|
+
LX.drawSpline = drawSpline;
|
|
6008
|
+
|
|
5958
6009
|
// area.js @jxarco
|
|
5959
6010
|
|
|
5960
6011
|
class Area {
|
|
@@ -6678,7 +6729,7 @@ class Area {
|
|
|
6678
6729
|
|
|
6679
6730
|
addSidebar( callback, options = {} ) {
|
|
6680
6731
|
|
|
6681
|
-
let sidebar = new LX.Sidebar( options );
|
|
6732
|
+
let sidebar = new LX.Sidebar( { callback, ...options } );
|
|
6682
6733
|
|
|
6683
6734
|
if( callback )
|
|
6684
6735
|
{
|
|
@@ -7004,8 +7055,8 @@ class Area {
|
|
|
7004
7055
|
}
|
|
7005
7056
|
}
|
|
7006
7057
|
}
|
|
7007
|
-
LX.Area = Area;
|
|
7008
|
-
|
|
7058
|
+
LX.Area = Area;
|
|
7059
|
+
|
|
7009
7060
|
// widget.js @jxarco
|
|
7010
7061
|
|
|
7011
7062
|
/**
|
|
@@ -12175,8 +12226,8 @@ class Map2D extends Widget {
|
|
|
12175
12226
|
}
|
|
12176
12227
|
}
|
|
12177
12228
|
|
|
12178
|
-
LX.Map2D = Map2D;
|
|
12179
|
-
|
|
12229
|
+
LX.Map2D = Map2D;
|
|
12230
|
+
|
|
12180
12231
|
// panel.js @jxarco
|
|
12181
12232
|
|
|
12182
12233
|
/**
|
|
@@ -13356,8 +13407,8 @@ class Panel {
|
|
|
13356
13407
|
}
|
|
13357
13408
|
}
|
|
13358
13409
|
|
|
13359
|
-
LX.Panel = Panel;
|
|
13360
|
-
|
|
13410
|
+
LX.Panel = Panel;
|
|
13411
|
+
|
|
13361
13412
|
// branch.js @jxarco
|
|
13362
13413
|
|
|
13363
13414
|
/**
|
|
@@ -13581,8 +13632,8 @@ class Branch {
|
|
|
13581
13632
|
}
|
|
13582
13633
|
}
|
|
13583
13634
|
}
|
|
13584
|
-
LX.Branch = Branch;
|
|
13585
|
-
|
|
13635
|
+
LX.Branch = Branch;
|
|
13636
|
+
|
|
13586
13637
|
// menubar.js @jxarco
|
|
13587
13638
|
|
|
13588
13639
|
/**
|
|
@@ -13899,8 +13950,8 @@ class Menubar {
|
|
|
13899
13950
|
}
|
|
13900
13951
|
}
|
|
13901
13952
|
}
|
|
13902
|
-
LX.Menubar = Menubar;
|
|
13903
|
-
|
|
13953
|
+
LX.Menubar = Menubar;
|
|
13954
|
+
|
|
13904
13955
|
// sidebar.js @jxarco
|
|
13905
13956
|
|
|
13906
13957
|
/**
|
|
@@ -13936,6 +13987,7 @@ class Sidebar {
|
|
|
13936
13987
|
|
|
13937
13988
|
this.root = document.createElement( "div" );
|
|
13938
13989
|
this.root.className = "lexsidebar " + ( options.className ?? "" );
|
|
13990
|
+
this.callback = options.callback ?? null;
|
|
13939
13991
|
|
|
13940
13992
|
this._displaySelected = options.displaySelected ?? false;
|
|
13941
13993
|
|
|
@@ -13952,17 +14004,19 @@ class Sidebar {
|
|
|
13952
14004
|
configurable: true
|
|
13953
14005
|
});
|
|
13954
14006
|
|
|
14007
|
+
const mobile = navigator && /Android|iPhone/i.test( navigator.userAgent );
|
|
14008
|
+
|
|
13955
14009
|
this.side = options.side ?? "left";
|
|
13956
14010
|
this.collapsable = options.collapsable ?? true;
|
|
13957
14011
|
this._collapseWidth = ( options.collapseToIcons ?? true ) ? "58px" : "0px";
|
|
13958
|
-
this.collapsed =
|
|
14012
|
+
this.collapsed = options.collapsed ?? mobile;
|
|
13959
14013
|
|
|
13960
14014
|
this.filterString = "";
|
|
13961
14015
|
|
|
13962
14016
|
LX.doAsync( () => {
|
|
13963
14017
|
|
|
13964
14018
|
this.root.parentElement.ogWidth = this.root.parentElement.style.width;
|
|
13965
|
-
this.root.parentElement.style.transition = "width 0.25s ease-out";
|
|
14019
|
+
this.root.parentElement.style.transition = this.collapsed ? "" : "width 0.25s ease-out";
|
|
13966
14020
|
|
|
13967
14021
|
this.resizeObserver = new ResizeObserver( entries => {
|
|
13968
14022
|
for ( const entry of entries )
|
|
@@ -13971,6 +14025,24 @@ class Sidebar {
|
|
|
13971
14025
|
}
|
|
13972
14026
|
});
|
|
13973
14027
|
|
|
14028
|
+
if( this.collapsed )
|
|
14029
|
+
{
|
|
14030
|
+
this.root.classList.toggle( "collapsed", this.collapsed );
|
|
14031
|
+
this.root.parentElement.style.width = this._collapseWidth;
|
|
14032
|
+
|
|
14033
|
+
if( !this.resizeObserver )
|
|
14034
|
+
{
|
|
14035
|
+
throw( "Wait until ResizeObserver has been created!" );
|
|
14036
|
+
}
|
|
14037
|
+
|
|
14038
|
+
this.resizeObserver.observe( this.root.parentElement );
|
|
14039
|
+
|
|
14040
|
+
LX.doAsync( () => {
|
|
14041
|
+
this.resizeObserver.unobserve( this.root.parentElement );
|
|
14042
|
+
this.root.querySelectorAll( ".lexsidebarentrycontent" ).forEach( e => e.dataset[ "disableTooltip" ] = !this.collapsed );
|
|
14043
|
+
}, 10 );
|
|
14044
|
+
}
|
|
14045
|
+
|
|
13974
14046
|
}, 10 );
|
|
13975
14047
|
|
|
13976
14048
|
// Header
|
|
@@ -13986,11 +14058,29 @@ class Sidebar {
|
|
|
13986
14058
|
const icon = LX.makeIcon( this.side == "left" ? "PanelLeft" : "PanelRight", { title: "Toggle Sidebar", iconClass: "toggler" } );
|
|
13987
14059
|
this.header.appendChild( icon );
|
|
13988
14060
|
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
14061
|
+
if( mobile )
|
|
14062
|
+
{
|
|
14063
|
+
// create an area and append a sidebar:
|
|
14064
|
+
const area = new LX.Area({ skipAppend: true });
|
|
14065
|
+
const sheetSidebarOptions = LX.deepCopy( options );
|
|
14066
|
+
sheetSidebarOptions.collapsed = false;
|
|
14067
|
+
sheetSidebarOptions.collapsable = false;
|
|
14068
|
+
area.addSidebar( this.callback, sheetSidebarOptions );
|
|
14069
|
+
|
|
14070
|
+
icon.addEventListener( "click", e => {
|
|
14071
|
+
e.preventDefault();
|
|
14072
|
+
e.stopPropagation();
|
|
14073
|
+
new LX.Sheet("256px", [ area ], { side: this.side } );
|
|
14074
|
+
} );
|
|
14075
|
+
}
|
|
14076
|
+
else
|
|
14077
|
+
{
|
|
14078
|
+
icon.addEventListener( "click", e => {
|
|
14079
|
+
e.preventDefault();
|
|
14080
|
+
e.stopPropagation();
|
|
14081
|
+
this.toggleCollapsed();
|
|
14082
|
+
} );
|
|
14083
|
+
}
|
|
13994
14084
|
}
|
|
13995
14085
|
}
|
|
13996
14086
|
|
|
@@ -14430,20 +14520,17 @@ class Sidebar {
|
|
|
14430
14520
|
return;
|
|
14431
14521
|
}
|
|
14432
14522
|
|
|
14523
|
+
const f = options.callback;
|
|
14524
|
+
if( f ) f.call( this, key, item.value, e );
|
|
14525
|
+
|
|
14433
14526
|
if( isCollapsable )
|
|
14434
14527
|
{
|
|
14435
14528
|
itemDom.querySelector( ".collapser" ).click();
|
|
14436
14529
|
}
|
|
14437
|
-
else
|
|
14530
|
+
else if( item.checkbox )
|
|
14438
14531
|
{
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
if( item.checkbox )
|
|
14443
|
-
{
|
|
14444
|
-
item.value = !item.value;
|
|
14445
|
-
item.checkbox.set( item.value, true );
|
|
14446
|
-
}
|
|
14532
|
+
item.value = !item.value;
|
|
14533
|
+
item.checkbox.set( item.value, true );
|
|
14447
14534
|
}
|
|
14448
14535
|
|
|
14449
14536
|
// Manage selected
|
|
@@ -14547,8 +14634,8 @@ class Sidebar {
|
|
|
14547
14634
|
}
|
|
14548
14635
|
}
|
|
14549
14636
|
}
|
|
14550
|
-
LX.Sidebar = Sidebar;
|
|
14551
|
-
|
|
14637
|
+
LX.Sidebar = Sidebar;
|
|
14638
|
+
|
|
14552
14639
|
// asset_view.js @jxarco
|
|
14553
14640
|
|
|
14554
14641
|
class AssetViewEvent {
|
|
@@ -15415,6 +15502,6 @@ class AssetView {
|
|
|
15415
15502
|
}
|
|
15416
15503
|
}
|
|
15417
15504
|
|
|
15418
|
-
LX.AssetView = AssetView;
|
|
15419
|
-
|
|
15420
|
-
export { ADD_CUSTOM_WIDGET, Area, AssetView, AssetViewEvent, Branch, LX, Menubar, Panel, Sidebar, Widget };
|
|
15505
|
+
LX.AssetView = AssetView;
|
|
15506
|
+
|
|
15507
|
+
export { ADD_CUSTOM_WIDGET, Area, AssetView, AssetViewEvent, Branch, LX, Menubar, Panel, Sidebar, Widget };
|