lexgui 0.6.10 → 0.6.12
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/README.md +3 -3
- package/build/components/codeeditor.js +14 -11
- package/build/components/docmaker.js +2 -2
- package/build/components/timeline.js +127 -71
- package/build/lexgui-docs.css +0 -2
- package/build/lexgui.css +39 -0
- package/build/lexgui.js +710 -80
- package/build/lexgui.min.css +1 -1
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +732 -102
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +32 -1
- package/demo.js +35 -1
- package/examples/all_widgets.html +1 -0
- package/examples/editor.html +1 -1
- package/examples/timeline.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.12",
|
|
11
11
|
ready: false,
|
|
12
12
|
components: [], // Specific pre-build components
|
|
13
13
|
signals: {}, // Events and triggers
|
|
@@ -718,8 +718,6 @@ class Popover {
|
|
|
718
718
|
|
|
719
719
|
constructor( trigger, content, options = {} ) {
|
|
720
720
|
|
|
721
|
-
console.assert( trigger, "Popover needs a DOM element as trigger!" );
|
|
722
|
-
|
|
723
721
|
if( Popover.activeElement )
|
|
724
722
|
{
|
|
725
723
|
Popover.activeElement.destroy();
|
|
@@ -727,13 +725,20 @@ class Popover {
|
|
|
727
725
|
}
|
|
728
726
|
|
|
729
727
|
this._trigger = trigger;
|
|
730
|
-
|
|
731
|
-
trigger
|
|
728
|
+
|
|
729
|
+
if( trigger )
|
|
730
|
+
{
|
|
731
|
+
trigger.classList.add( "triggered" );
|
|
732
|
+
trigger.active = this;
|
|
733
|
+
}
|
|
732
734
|
|
|
733
735
|
this._windowPadding = 4;
|
|
734
736
|
this.side = options.side ?? "bottom";
|
|
735
737
|
this.align = options.align ?? "center";
|
|
738
|
+
this.sideOffset = options.sideOffset ?? 0;
|
|
739
|
+
this.alignOffset = options.alignOffset ?? 0;
|
|
736
740
|
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
741
|
+
this.reference = options.reference;
|
|
737
742
|
|
|
738
743
|
this.root = document.createElement( "div" );
|
|
739
744
|
this.root.dataset["side"] = this.side;
|
|
@@ -768,29 +773,35 @@ class Popover {
|
|
|
768
773
|
LX.doAsync( () => {
|
|
769
774
|
this._adjustPosition();
|
|
770
775
|
|
|
771
|
-
this.
|
|
776
|
+
if( this._trigger )
|
|
777
|
+
{
|
|
778
|
+
this.root.focus();
|
|
772
779
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
+
this._onClick = e => {
|
|
781
|
+
if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
|
|
782
|
+
{
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
this.destroy();
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
789
|
+
document.body.addEventListener( "focusin", this._onClick, true );
|
|
790
|
+
}
|
|
780
791
|
|
|
781
|
-
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
782
|
-
document.body.addEventListener( "focusin", this._onClick, true );
|
|
783
792
|
}, 10 );
|
|
784
793
|
}
|
|
785
794
|
|
|
786
795
|
destroy() {
|
|
787
796
|
|
|
788
|
-
this._trigger
|
|
789
|
-
|
|
790
|
-
|
|
797
|
+
if( this._trigger )
|
|
798
|
+
{
|
|
799
|
+
this._trigger.classList.remove( "triggered" );
|
|
800
|
+
delete this._trigger.active;
|
|
791
801
|
|
|
792
|
-
|
|
793
|
-
|
|
802
|
+
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
803
|
+
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
804
|
+
}
|
|
794
805
|
|
|
795
806
|
this.root.remove();
|
|
796
807
|
|
|
@@ -803,26 +814,28 @@ class Popover {
|
|
|
803
814
|
|
|
804
815
|
// Place menu using trigger position and user options
|
|
805
816
|
{
|
|
806
|
-
const
|
|
817
|
+
const el = this.reference ?? this._trigger;
|
|
818
|
+
console.assert( el, "Popover needs a trigger or reference element!" );
|
|
819
|
+
const rect = el.getBoundingClientRect();
|
|
807
820
|
|
|
808
821
|
let alignWidth = true;
|
|
809
822
|
|
|
810
823
|
switch( this.side )
|
|
811
824
|
{
|
|
812
825
|
case "left":
|
|
813
|
-
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
826
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth - this.sideOffset );
|
|
814
827
|
alignWidth = false;
|
|
815
828
|
break;
|
|
816
829
|
case "right":
|
|
817
|
-
position[ 0 ] += ( rect.x + rect.width );
|
|
830
|
+
position[ 0 ] += ( rect.x + rect.width + this.sideOffset );
|
|
818
831
|
alignWidth = false;
|
|
819
832
|
break;
|
|
820
833
|
case "top":
|
|
821
|
-
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
834
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight - this.sideOffset );
|
|
822
835
|
alignWidth = true;
|
|
823
836
|
break;
|
|
824
837
|
case "bottom":
|
|
825
|
-
position[ 1 ] += ( rect.y + rect.height );
|
|
838
|
+
position[ 1 ] += ( rect.y + rect.height + this.sideOffset );
|
|
826
839
|
alignWidth = true;
|
|
827
840
|
break;
|
|
828
841
|
}
|
|
@@ -842,6 +855,9 @@ class Popover {
|
|
|
842
855
|
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
843
856
|
break;
|
|
844
857
|
}
|
|
858
|
+
|
|
859
|
+
if( alignWidth ) { position[ 0 ] += this.alignOffset; }
|
|
860
|
+
else { position[ 1 ] += this.alignOffset; }
|
|
845
861
|
}
|
|
846
862
|
|
|
847
863
|
if( this.avoidCollisions )
|
|
@@ -856,6 +872,58 @@ class Popover {
|
|
|
856
872
|
}
|
|
857
873
|
LX.Popover = Popover;
|
|
858
874
|
|
|
875
|
+
/**
|
|
876
|
+
* @class PopConfirm
|
|
877
|
+
*/
|
|
878
|
+
|
|
879
|
+
class PopConfirm {
|
|
880
|
+
|
|
881
|
+
constructor( reference, options = {} ) {
|
|
882
|
+
|
|
883
|
+
const okText = options.confirmText ?? "Yes";
|
|
884
|
+
const cancelText = options.cancelText ?? "No";
|
|
885
|
+
const title = options.title ?? "Confirm";
|
|
886
|
+
const content = options.content ?? "Are you sure you want to proceed?";
|
|
887
|
+
const onConfirm = options.onConfirm;
|
|
888
|
+
const onCancel = options.onCancel;
|
|
889
|
+
|
|
890
|
+
const popoverContainer = LX.makeContainer( ["auto", "auto"], "tour-step-container" );
|
|
891
|
+
|
|
892
|
+
{
|
|
893
|
+
const headerDiv = LX.makeContainer( ["100%", "auto"], "flex flex-row", "", popoverContainer );
|
|
894
|
+
LX.makeContainer( ["100%", "auto"], "p-1 font-medium text-md", title, headerDiv );
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
LX.makeContainer( ["100%", "auto"], "p-1 text-md", content, popoverContainer, { maxWidth: "400px" } );
|
|
898
|
+
const footer = LX.makeContainer( ["100%", "auto"], "flex flex-row text-md", "", popoverContainer );
|
|
899
|
+
const footerButtons = LX.makeContainer( ["100%", "auto"], "text-md", "", footer );
|
|
900
|
+
const footerPanel = new LX.Panel();
|
|
901
|
+
footerButtons.appendChild( footerPanel.root );
|
|
902
|
+
|
|
903
|
+
footerPanel.sameLine( 2, "justify-end" );
|
|
904
|
+
footerPanel.addButton( null, cancelText, () => {
|
|
905
|
+
if( onCancel ) onCancel();
|
|
906
|
+
this._popover?.destroy();
|
|
907
|
+
}, { xbuttonClass: "contrast" } );
|
|
908
|
+
footerPanel.addButton( null, okText, () => {
|
|
909
|
+
if( onConfirm ) onConfirm();
|
|
910
|
+
this._popover?.destroy();
|
|
911
|
+
}, { buttonClass: "accent" } );
|
|
912
|
+
|
|
913
|
+
this._popover?.destroy();
|
|
914
|
+
this._popover = new LX.Popover( null, [ popoverContainer ], {
|
|
915
|
+
reference,
|
|
916
|
+
side: options.side ?? "top",
|
|
917
|
+
align: options.align,
|
|
918
|
+
sideOffset: options.sideOffset,
|
|
919
|
+
alignOffset: options.alignOffset,
|
|
920
|
+
} );
|
|
921
|
+
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
LX.PopConfirm = PopConfirm;
|
|
926
|
+
|
|
859
927
|
/**
|
|
860
928
|
* @class Sheet
|
|
861
929
|
*/
|
|
@@ -978,6 +1046,8 @@ class DropdownMenu {
|
|
|
978
1046
|
this._windowPadding = 4;
|
|
979
1047
|
this.side = options.side ?? "bottom";
|
|
980
1048
|
this.align = options.align ?? "center";
|
|
1049
|
+
this.sideOffset = options.sideOffset ?? 0;
|
|
1050
|
+
this.alignOffset = options.alignOffset ?? 0;
|
|
981
1051
|
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
982
1052
|
this.onBlur = options.onBlur;
|
|
983
1053
|
this.inPlace = false;
|
|
@@ -1220,19 +1290,19 @@ class DropdownMenu {
|
|
|
1220
1290
|
switch( this.side )
|
|
1221
1291
|
{
|
|
1222
1292
|
case "left":
|
|
1223
|
-
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
1293
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth - this.sideOffset );
|
|
1224
1294
|
alignWidth = false;
|
|
1225
1295
|
break;
|
|
1226
1296
|
case "right":
|
|
1227
|
-
position[ 0 ] += ( rect.x + rect.width );
|
|
1297
|
+
position[ 0 ] += ( rect.x + rect.width + this.sideOffset );
|
|
1228
1298
|
alignWidth = false;
|
|
1229
1299
|
break;
|
|
1230
1300
|
case "top":
|
|
1231
|
-
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
1301
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight - this.sideOffset );
|
|
1232
1302
|
alignWidth = true;
|
|
1233
1303
|
break;
|
|
1234
1304
|
case "bottom":
|
|
1235
|
-
position[ 1 ] += ( rect.y + rect.height );
|
|
1305
|
+
position[ 1 ] += ( rect.y + rect.height + this.sideOffset );
|
|
1236
1306
|
alignWidth = true;
|
|
1237
1307
|
break;
|
|
1238
1308
|
}
|
|
@@ -1252,6 +1322,9 @@ class DropdownMenu {
|
|
|
1252
1322
|
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
1253
1323
|
break;
|
|
1254
1324
|
}
|
|
1325
|
+
|
|
1326
|
+
if( alignWidth ) { position[ 0 ] += this.alignOffset; }
|
|
1327
|
+
else { position[ 1 ] += this.alignOffset; }
|
|
1255
1328
|
}
|
|
1256
1329
|
|
|
1257
1330
|
if( this.avoidCollisions )
|
|
@@ -1646,8 +1719,15 @@ class Calendar {
|
|
|
1646
1719
|
this.root = LX.makeContainer( ["256px", "auto"], "p-1 text-md" );
|
|
1647
1720
|
|
|
1648
1721
|
this.onChange = options.onChange;
|
|
1722
|
+
this.onPreviousMonth = options.onPreviousMonth;
|
|
1723
|
+
this.onNextMonth = options.onNextMonth;
|
|
1724
|
+
|
|
1649
1725
|
this.untilToday = options.untilToday;
|
|
1650
1726
|
this.fromToday = options.fromToday;
|
|
1727
|
+
this.range = options.range;
|
|
1728
|
+
|
|
1729
|
+
this.skipPrevMonth = options.skipPrevMonth;
|
|
1730
|
+
this.skipNextMonth = options.skipNextMonth;
|
|
1651
1731
|
|
|
1652
1732
|
if( dateString )
|
|
1653
1733
|
{
|
|
@@ -1671,7 +1751,7 @@ class Calendar {
|
|
|
1671
1751
|
}
|
|
1672
1752
|
}
|
|
1673
1753
|
|
|
1674
|
-
_previousMonth() {
|
|
1754
|
+
_previousMonth( skipCallback ) {
|
|
1675
1755
|
|
|
1676
1756
|
this.month = Math.max( 0, this.month - 1 );
|
|
1677
1757
|
|
|
@@ -1682,9 +1762,14 @@ class Calendar {
|
|
|
1682
1762
|
}
|
|
1683
1763
|
|
|
1684
1764
|
this.fromMonthYear( this.month, this.year );
|
|
1765
|
+
|
|
1766
|
+
if( !skipCallback && this.onPreviousMonth )
|
|
1767
|
+
{
|
|
1768
|
+
this.onPreviousMonth( this.currentDate );
|
|
1769
|
+
}
|
|
1685
1770
|
}
|
|
1686
1771
|
|
|
1687
|
-
_nextMonth() {
|
|
1772
|
+
_nextMonth( skipCallback ) {
|
|
1688
1773
|
|
|
1689
1774
|
this.month = Math.min( this.month + 1, 12 );
|
|
1690
1775
|
|
|
@@ -1695,6 +1780,11 @@ class Calendar {
|
|
|
1695
1780
|
}
|
|
1696
1781
|
|
|
1697
1782
|
this.fromMonthYear( this.month, this.year );
|
|
1783
|
+
|
|
1784
|
+
if( !skipCallback && this.onNextMonth )
|
|
1785
|
+
{
|
|
1786
|
+
this.onNextMonth( this.currentDate );
|
|
1787
|
+
}
|
|
1698
1788
|
}
|
|
1699
1789
|
|
|
1700
1790
|
refresh() {
|
|
@@ -1705,19 +1795,25 @@ class Calendar {
|
|
|
1705
1795
|
{
|
|
1706
1796
|
const header = LX.makeContainer( ["100%", "auto"], "flex flex-row p-1", "", this.root );
|
|
1707
1797
|
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1798
|
+
if( !this.skipPrevMonth )
|
|
1799
|
+
{
|
|
1800
|
+
const prevMonthIcon = LX.makeIcon( "Left", { title: "Previous Month", iconClass: "border p-1 rounded hover:bg-secondary", svgClass: "sm" } );
|
|
1801
|
+
header.appendChild( prevMonthIcon );
|
|
1802
|
+
prevMonthIcon.addEventListener( "click", () => {
|
|
1803
|
+
this._previousMonth();
|
|
1804
|
+
} );
|
|
1805
|
+
}
|
|
1713
1806
|
|
|
1714
1807
|
LX.makeContainer( ["100%", "auto"], "text-center font-medium select-none", `${ this.monthName } ${ this.year }`, header );
|
|
1715
1808
|
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1809
|
+
if( !this.skipNextMonth )
|
|
1810
|
+
{
|
|
1811
|
+
const nextMonthIcon = LX.makeIcon( "Right", { title: "Next Month", iconClass: "border p-1 rounded hover:bg-secondary", svgClass: "sm" } );
|
|
1812
|
+
header.appendChild( nextMonthIcon );
|
|
1813
|
+
nextMonthIcon.addEventListener( "click", () => {
|
|
1814
|
+
this._nextMonth();
|
|
1815
|
+
} );
|
|
1816
|
+
}
|
|
1721
1817
|
}
|
|
1722
1818
|
|
|
1723
1819
|
// Body
|
|
@@ -1749,6 +1845,11 @@ class Calendar {
|
|
|
1749
1845
|
const body = document.createElement( 'tbody' );
|
|
1750
1846
|
daysTable.appendChild( body );
|
|
1751
1847
|
|
|
1848
|
+
let fromRangeDate = this.range ? LX.dateFromDateString( this.range[ 0 ] ) : null;
|
|
1849
|
+
let toRangeDate = this.range ? LX.dateFromDateString( this.range[ 1 ] ) : null;
|
|
1850
|
+
|
|
1851
|
+
this.currentDate ? new Date( `${ this.currentDate.month }/${ this.currentDate.day }/${ this.currentDate.year }` ) : null;
|
|
1852
|
+
|
|
1752
1853
|
for( let week = 0; week < 6; week++ )
|
|
1753
1854
|
{
|
|
1754
1855
|
const hrow = document.createElement( 'tr' );
|
|
@@ -1761,15 +1862,28 @@ class Calendar {
|
|
|
1761
1862
|
|
|
1762
1863
|
const dayDate = new Date( `${ this.month }/${ dayData.day }/${ this.year }` );
|
|
1763
1864
|
const date = new Date();
|
|
1865
|
+
// today inclusives
|
|
1764
1866
|
const beforeToday = this.untilToday ? ( dayDate.getTime() < date.getTime() ) : true;
|
|
1765
|
-
const afterToday = this.fromToday ? ( dayDate.
|
|
1867
|
+
const afterToday = this.fromToday ? ( dayDate.getFullYear() > date.getFullYear() ||
|
|
1868
|
+
(dayDate.getFullYear() === date.getFullYear() && dayDate.getMonth() > date.getMonth()) ||
|
|
1869
|
+
(dayDate.getFullYear() === date.getFullYear() && dayDate.getMonth() === date.getMonth() && dayDate.getDate() >= date.getDate())
|
|
1870
|
+
) : true;
|
|
1766
1871
|
const selectable = dayData.currentMonth && beforeToday && afterToday;
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1872
|
+
const currentDay = this.currentDate && ( dayData.day == this.currentDate.day ) && ( this.month == this.currentDate.month )
|
|
1873
|
+
&& ( this.year == this.currentDate.year ) && dayData.currentMonth;
|
|
1874
|
+
const currentFromRange = selectable && fromRangeDate && ( dayData.day == fromRangeDate.getDate() ) && ( this.month == ( fromRangeDate.getMonth() + 1 ) )
|
|
1875
|
+
&& ( this.year == fromRangeDate.getFullYear() );
|
|
1876
|
+
const currentToRange = selectable && toRangeDate && ( dayData.day == toRangeDate.getDate() ) && ( this.month == ( toRangeDate.getMonth() + 1 ) )
|
|
1877
|
+
&& ( this.year == toRangeDate.getFullYear() );
|
|
1878
|
+
|
|
1879
|
+
if( ( !this.range && currentDay ) || this.range && ( currentFromRange || currentToRange ) )
|
|
1770
1880
|
{
|
|
1771
1881
|
th.className += ` bg-contrast fg-contrast`;
|
|
1772
1882
|
}
|
|
1883
|
+
else if( this.range && selectable && ( dayDate > fromRangeDate ) && ( dayDate < toRangeDate ) )
|
|
1884
|
+
{
|
|
1885
|
+
th.className += ` bg-accent fg-contrast`;
|
|
1886
|
+
}
|
|
1773
1887
|
else
|
|
1774
1888
|
{
|
|
1775
1889
|
th.className += ` ${ selectable ? "fg-primary" : "fg-tertiary" } hover:bg-secondary`;
|
|
@@ -1789,6 +1903,20 @@ class Calendar {
|
|
|
1789
1903
|
}
|
|
1790
1904
|
} );
|
|
1791
1905
|
}
|
|
1906
|
+
// This event should only be applied in non current month days
|
|
1907
|
+
else if( this.range === undefined && !dayData.currentMonth )
|
|
1908
|
+
{
|
|
1909
|
+
th.addEventListener( "click", () => {
|
|
1910
|
+
if( dayData?.prevMonth )
|
|
1911
|
+
{
|
|
1912
|
+
this._previousMonth();
|
|
1913
|
+
}
|
|
1914
|
+
else
|
|
1915
|
+
{
|
|
1916
|
+
this._nextMonth();
|
|
1917
|
+
}
|
|
1918
|
+
} );
|
|
1919
|
+
}
|
|
1792
1920
|
}
|
|
1793
1921
|
|
|
1794
1922
|
body.appendChild( hrow );
|
|
@@ -1803,6 +1931,7 @@ class Calendar {
|
|
|
1803
1931
|
|
|
1804
1932
|
this.day = parseInt( tokens[ 0 ] );
|
|
1805
1933
|
this.month = parseInt( tokens[ 1 ] );
|
|
1934
|
+
this.monthName = this.getMonthName( this.month - 1 );
|
|
1806
1935
|
this.year = parseInt( tokens[ 2 ] );
|
|
1807
1936
|
|
|
1808
1937
|
this.currentDate = this._getCurrentDate();
|
|
@@ -1832,7 +1961,7 @@ class Calendar {
|
|
|
1832
1961
|
// Fill in days from previous month
|
|
1833
1962
|
for( let i = firstDay - 1; i >= 0; i--)
|
|
1834
1963
|
{
|
|
1835
|
-
calendarDays.push( { day: daysInPrevMonth - i, currentMonth: false } );
|
|
1964
|
+
calendarDays.push( { day: daysInPrevMonth - i, currentMonth: false, prevMonth: true } );
|
|
1836
1965
|
}
|
|
1837
1966
|
|
|
1838
1967
|
// Fill in current month days
|
|
@@ -1845,7 +1974,7 @@ class Calendar {
|
|
|
1845
1974
|
const remaining = 42 - calendarDays.length;
|
|
1846
1975
|
for( let i = 1; i <= remaining; i++ )
|
|
1847
1976
|
{
|
|
1848
|
-
calendarDays.push( { day: i, currentMonth: false } );
|
|
1977
|
+
calendarDays.push( { day: i, currentMonth: false, nextMonth: true } );
|
|
1849
1978
|
}
|
|
1850
1979
|
|
|
1851
1980
|
this.monthName = this.getMonthName( month );
|
|
@@ -1861,8 +1990,14 @@ class Calendar {
|
|
|
1861
1990
|
return formatter.format( new Date( 2000, monthIndex, 1 ) );
|
|
1862
1991
|
}
|
|
1863
1992
|
|
|
1864
|
-
getFullDate() {
|
|
1865
|
-
return `${ this.monthName } ${ this.day }${ this._getOrdinalSuffix( this.day ) }, ${ this.year }`;
|
|
1993
|
+
getFullDate( monthName, day, year ) {
|
|
1994
|
+
return `${ monthName ?? this.monthName } ${ day ?? this.day }${ this._getOrdinalSuffix( day ?? this.day ) }, ${ year ?? this.year }`;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
setRange( range ) {
|
|
1998
|
+
console.assert( range.constructor === Array, "Date Range must be in Array format" );
|
|
1999
|
+
this.range = range;
|
|
2000
|
+
this.refresh();
|
|
1866
2001
|
}
|
|
1867
2002
|
|
|
1868
2003
|
_getOrdinalSuffix( day ) {
|
|
@@ -1879,6 +2014,110 @@ class Calendar {
|
|
|
1879
2014
|
|
|
1880
2015
|
LX.Calendar = Calendar;
|
|
1881
2016
|
|
|
2017
|
+
class CalendarRange {
|
|
2018
|
+
|
|
2019
|
+
/**
|
|
2020
|
+
* @constructor CalendarRange
|
|
2021
|
+
* @param {Array} range ["DD/MM/YYYY", "DD/MM/YYYY"]
|
|
2022
|
+
* @param {Object} options
|
|
2023
|
+
*/
|
|
2024
|
+
|
|
2025
|
+
constructor( range, options = {} ) {
|
|
2026
|
+
|
|
2027
|
+
this.root = LX.makeContainer( ["auto", "auto"], "flex flex-row" );
|
|
2028
|
+
|
|
2029
|
+
console.assert( range && range.constructor === Array, "Range cannot be empty and has to be an Array!" );
|
|
2030
|
+
|
|
2031
|
+
let mustAdvanceMonth = false;
|
|
2032
|
+
|
|
2033
|
+
// Fix any issues with date range picking
|
|
2034
|
+
{
|
|
2035
|
+
const t0 = LX.dateFromDateString( range[ 0 ] );
|
|
2036
|
+
const t1 = LX.dateFromDateString( range[ 1 ] );
|
|
2037
|
+
|
|
2038
|
+
if( t0 > t1 )
|
|
2039
|
+
{
|
|
2040
|
+
const tmp = range[ 0 ];
|
|
2041
|
+
range[ 0 ] = range[ 1 ];
|
|
2042
|
+
range[ 1 ] = tmp;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
mustAdvanceMonth = ( t0.getMonth() == t1.getMonth() ) && ( t0.getFullYear() == t1.getFullYear() );
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
this.from = range[ 0 ];
|
|
2049
|
+
this.to = range[ 1 ];
|
|
2050
|
+
|
|
2051
|
+
this._selectingRange = false;
|
|
2052
|
+
|
|
2053
|
+
const onChange = ( date ) => {
|
|
2054
|
+
|
|
2055
|
+
const newDateString = `${ date.day }/${ date.month }/${ date.year }`;
|
|
2056
|
+
|
|
2057
|
+
if( !this._selectingRange )
|
|
2058
|
+
{
|
|
2059
|
+
this.from = this.to = newDateString;
|
|
2060
|
+
this._selectingRange = true;
|
|
2061
|
+
}
|
|
2062
|
+
else
|
|
2063
|
+
{
|
|
2064
|
+
this.to = newDateString;
|
|
2065
|
+
this._selectingRange = false;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
const newRange = [ this.from, this.to ];
|
|
2069
|
+
|
|
2070
|
+
this.fromCalendar.setRange( newRange );
|
|
2071
|
+
this.toCalendar.setRange( newRange );
|
|
2072
|
+
|
|
2073
|
+
if( options.onChange )
|
|
2074
|
+
{
|
|
2075
|
+
options.onChange( newRange );
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
};
|
|
2079
|
+
|
|
2080
|
+
this.fromCalendar = new LX.Calendar( this.from, {
|
|
2081
|
+
skipNextMonth: true,
|
|
2082
|
+
onChange,
|
|
2083
|
+
onPreviousMonth: () => {
|
|
2084
|
+
this.toCalendar._previousMonth();
|
|
2085
|
+
},
|
|
2086
|
+
range
|
|
2087
|
+
});
|
|
2088
|
+
|
|
2089
|
+
this.toCalendar = new LX.Calendar( this.to, {
|
|
2090
|
+
skipPrevMonth: true,
|
|
2091
|
+
onChange,
|
|
2092
|
+
onNextMonth: () => {
|
|
2093
|
+
this.fromCalendar._nextMonth();
|
|
2094
|
+
},
|
|
2095
|
+
range
|
|
2096
|
+
});
|
|
2097
|
+
|
|
2098
|
+
if( mustAdvanceMonth )
|
|
2099
|
+
{
|
|
2100
|
+
this.toCalendar._nextMonth( true );
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
this.root.appendChild( this.fromCalendar.root );
|
|
2104
|
+
this.root.appendChild( this.toCalendar.root );
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
getFullDate() {
|
|
2108
|
+
|
|
2109
|
+
const d0 = LX.dateFromDateString( this.from );
|
|
2110
|
+
const d0Month = this.fromCalendar.getMonthName( d0.getMonth() );
|
|
2111
|
+
|
|
2112
|
+
const d1 = LX.dateFromDateString( this.to );
|
|
2113
|
+
const d1Month = this.toCalendar.getMonthName( d1.getMonth() );
|
|
2114
|
+
|
|
2115
|
+
return `${ this.fromCalendar.getFullDate( d0Month, d0.getDate(), d0.getFullYear() ) } to ${ this.toCalendar.getFullDate( d1Month, d1.getDate(), d1.getFullYear() ) }`;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
LX.CalendarRange = CalendarRange;
|
|
2120
|
+
|
|
1882
2121
|
/**
|
|
1883
2122
|
* @class Tabs
|
|
1884
2123
|
*/
|
|
@@ -4113,8 +4352,8 @@ Element.prototype.ignore = function( eventName, callbackName ) {
|
|
|
4113
4352
|
callbackName = callbackName ?? ( "_on" + eventName );
|
|
4114
4353
|
const callback = this[ callbackName ];
|
|
4115
4354
|
this.removeEventListener( eventName, callback );
|
|
4116
|
-
};
|
|
4117
|
-
|
|
4355
|
+
};
|
|
4356
|
+
|
|
4118
4357
|
// icons.js @jxarco
|
|
4119
4358
|
|
|
4120
4359
|
const RAW_ICONS = {
|
|
@@ -4292,8 +4531,8 @@ LX.LucideIconAlias = {
|
|
|
4292
4531
|
"RotateRight": "RotateCw",
|
|
4293
4532
|
"RotateBack": "RotateCcw",
|
|
4294
4533
|
"RotateLeft": "RotateCcw",
|
|
4295
|
-
};
|
|
4296
|
-
|
|
4534
|
+
};
|
|
4535
|
+
|
|
4297
4536
|
// utils.js @jxarco
|
|
4298
4537
|
|
|
4299
4538
|
function clamp( num, min, max ) { return Math.min( Math.max( num, min ), max ); }
|
|
@@ -4729,6 +4968,22 @@ function hsvToRgb( hsv )
|
|
|
4729
4968
|
|
|
4730
4969
|
LX.hsvToRgb = hsvToRgb;
|
|
4731
4970
|
|
|
4971
|
+
/**
|
|
4972
|
+
* @method dateFromDateString
|
|
4973
|
+
* @description Get an instance of Date() from a Date in String format (DD/MM/YYYY)
|
|
4974
|
+
* @param {String} dateString
|
|
4975
|
+
*/
|
|
4976
|
+
function dateFromDateString( dateString )
|
|
4977
|
+
{
|
|
4978
|
+
const tokens = dateString.split( '/' );
|
|
4979
|
+
const day = parseInt( tokens[ 0 ] );
|
|
4980
|
+
const month = parseInt( tokens[ 1 ] );
|
|
4981
|
+
const year = parseInt( tokens[ 2 ] );
|
|
4982
|
+
return new Date( `${ month }/${ day }/${ year }` );
|
|
4983
|
+
}
|
|
4984
|
+
|
|
4985
|
+
LX.dateFromDateString = dateFromDateString;
|
|
4986
|
+
|
|
4732
4987
|
/**
|
|
4733
4988
|
* @method measureRealWidth
|
|
4734
4989
|
* @description Measure the pixel width of a text
|
|
@@ -6009,8 +6264,8 @@ function drawSpline( ctx, pts, t )
|
|
|
6009
6264
|
ctx.restore();
|
|
6010
6265
|
}
|
|
6011
6266
|
|
|
6012
|
-
LX.drawSpline = drawSpline;
|
|
6013
|
-
|
|
6267
|
+
LX.drawSpline = drawSpline;
|
|
6268
|
+
|
|
6014
6269
|
// area.js @jxarco
|
|
6015
6270
|
|
|
6016
6271
|
class AreaOverlayButtons {
|
|
@@ -7104,8 +7359,8 @@ class Area {
|
|
|
7104
7359
|
}
|
|
7105
7360
|
}
|
|
7106
7361
|
}
|
|
7107
|
-
LX.Area = Area;
|
|
7108
|
-
|
|
7362
|
+
LX.Area = Area;
|
|
7363
|
+
|
|
7109
7364
|
// widget.js @jxarco
|
|
7110
7365
|
|
|
7111
7366
|
/**
|
|
@@ -8660,6 +8915,20 @@ class Button extends Widget {
|
|
|
8660
8915
|
{
|
|
8661
8916
|
wValue.querySelector( ".file-input" ).click();
|
|
8662
8917
|
}
|
|
8918
|
+
else if( options.mustConfirm )
|
|
8919
|
+
{
|
|
8920
|
+
new LX.PopConfirm( wValue, {
|
|
8921
|
+
onConfirm: () => {
|
|
8922
|
+
this._trigger( new LX.IEvent( name, value, e ), callback );
|
|
8923
|
+
},
|
|
8924
|
+
side: options.confirmSide,
|
|
8925
|
+
align: options.confirmAlign,
|
|
8926
|
+
confirmText: options.confirmText,
|
|
8927
|
+
cancelText: options.confirmCancelText,
|
|
8928
|
+
title: options.confirmTitle,
|
|
8929
|
+
content: options.confirmContent
|
|
8930
|
+
} );
|
|
8931
|
+
}
|
|
8663
8932
|
else
|
|
8664
8933
|
{
|
|
8665
8934
|
const swapInput = wValue.querySelector( "input" );
|
|
@@ -8955,16 +9224,17 @@ class Form extends Widget {
|
|
|
8955
9224
|
|
|
8956
9225
|
if( entryData.constructor != Object )
|
|
8957
9226
|
{
|
|
8958
|
-
|
|
9227
|
+
const oldValue = JSON.parse( JSON.stringify( entryData ) );
|
|
9228
|
+
entryData = { value: oldValue };
|
|
8959
9229
|
data[ entry ] = entryData;
|
|
8960
9230
|
}
|
|
8961
9231
|
|
|
8962
|
-
entryData.placeholder = entryData.placeholder ?? entry;
|
|
9232
|
+
entryData.placeholder = entryData.placeholder ?? ( entryData.label ?? `Enter ${ entry }` );
|
|
8963
9233
|
entryData.width = "100%";
|
|
8964
9234
|
|
|
8965
9235
|
if( !( options.skipLabels ?? false ) )
|
|
8966
9236
|
{
|
|
8967
|
-
const label = new LX.TextInput( null, entry, null, { disabled: true, inputClass: "formlabel nobg" } );
|
|
9237
|
+
const label = new LX.TextInput( null, entryData.label ?? entry, null, { disabled: true, inputClass: "formlabel nobg" } );
|
|
8968
9238
|
container.appendChild( label.root );
|
|
8969
9239
|
}
|
|
8970
9240
|
|
|
@@ -10659,15 +10929,15 @@ class Vector extends Widget {
|
|
|
10659
10929
|
|
|
10660
10930
|
for( let i = 0; i < vectorInputs.length; ++i )
|
|
10661
10931
|
{
|
|
10662
|
-
let
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
vectorInputs[ i ].value =
|
|
10932
|
+
let vecValue = newValue[ i ];
|
|
10933
|
+
vecValue = LX.clamp( vecValue, +vectorInputs[ i ].min, +vectorInputs[ i ].max );
|
|
10934
|
+
vecValue = LX.round( vecValue, options.precision ) ?? 0;
|
|
10935
|
+
vectorInputs[ i ].value = value[ i ] = vecValue;
|
|
10666
10936
|
}
|
|
10667
10937
|
|
|
10668
10938
|
if( !skipCallback )
|
|
10669
10939
|
{
|
|
10670
|
-
this._trigger( new LX.IEvent( name,
|
|
10940
|
+
this._trigger( new LX.IEvent( name, value, event ), callback );
|
|
10671
10941
|
}
|
|
10672
10942
|
};
|
|
10673
10943
|
|
|
@@ -11257,12 +11527,18 @@ class Progress extends Widget {
|
|
|
11257
11527
|
};
|
|
11258
11528
|
|
|
11259
11529
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
11530
|
+
newValue = LX.clamp( newValue, progress.min, progress.max );
|
|
11260
11531
|
this.root.querySelector("meter").value = newValue;
|
|
11261
11532
|
_updateColor();
|
|
11262
11533
|
if( this.root.querySelector("span") )
|
|
11263
11534
|
{
|
|
11264
11535
|
this.root.querySelector("span").innerText = newValue;
|
|
11265
11536
|
}
|
|
11537
|
+
|
|
11538
|
+
if( !skipCallback )
|
|
11539
|
+
{
|
|
11540
|
+
this._trigger( new LX.IEvent( name, newValue, event ), options.callback );
|
|
11541
|
+
}
|
|
11266
11542
|
};
|
|
11267
11543
|
|
|
11268
11544
|
this.onResize = ( rect ) => {
|
|
@@ -11346,11 +11622,6 @@ class Progress extends Widget {
|
|
|
11346
11622
|
const rect = progress.getBoundingClientRect();
|
|
11347
11623
|
const newValue = LX.round( LX.remapRange( e.offsetX - rect.x, 0, rect.width, progress.min, progress.max ) );
|
|
11348
11624
|
this.set( newValue, false, e );
|
|
11349
|
-
|
|
11350
|
-
if( options.callback )
|
|
11351
|
-
{
|
|
11352
|
-
options.callback( newValue, e );
|
|
11353
|
-
}
|
|
11354
11625
|
}
|
|
11355
11626
|
|
|
11356
11627
|
e.stopPropagation();
|
|
@@ -12413,25 +12684,30 @@ LX.Table = Table;
|
|
|
12413
12684
|
|
|
12414
12685
|
class DatePicker extends Widget {
|
|
12415
12686
|
|
|
12416
|
-
constructor( name,
|
|
12687
|
+
constructor( name, dateValue, callback, options = { } ) {
|
|
12417
12688
|
|
|
12418
12689
|
super( Widget.DATE, name, null, options );
|
|
12419
12690
|
|
|
12420
|
-
|
|
12691
|
+
const dateAsRange = ( dateValue?.constructor === Array );
|
|
12692
|
+
|
|
12693
|
+
if( !dateAsRange && options.today )
|
|
12421
12694
|
{
|
|
12422
12695
|
const date = new Date();
|
|
12423
|
-
|
|
12696
|
+
dateValue = `${ date.getDate() }/${ date.getMonth() + 1 }/${ date.getFullYear() }`;
|
|
12424
12697
|
}
|
|
12425
12698
|
|
|
12426
12699
|
this.onGetValue = () => {
|
|
12427
|
-
return
|
|
12700
|
+
return dateValue;
|
|
12428
12701
|
};
|
|
12429
12702
|
|
|
12430
12703
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
12431
12704
|
|
|
12432
|
-
|
|
12705
|
+
if( !dateAsRange )
|
|
12706
|
+
{
|
|
12707
|
+
this.calendar.fromDateString( newValue );
|
|
12708
|
+
}
|
|
12433
12709
|
|
|
12434
|
-
|
|
12710
|
+
dateValue = newValue;
|
|
12435
12711
|
|
|
12436
12712
|
refresh( this.calendar.getFullDate() );
|
|
12437
12713
|
|
|
@@ -12446,26 +12722,80 @@ class DatePicker extends Widget {
|
|
|
12446
12722
|
container.style.width = `calc( 100% - ${ realNameWidth })`;
|
|
12447
12723
|
};
|
|
12448
12724
|
|
|
12449
|
-
const container =
|
|
12450
|
-
container.className = "lexdate";
|
|
12725
|
+
const container = LX.makeContainer( [ "auto", "auto" ], "lexdate flex flex-row" );
|
|
12451
12726
|
this.root.appendChild( container );
|
|
12452
12727
|
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12728
|
+
if( !dateAsRange )
|
|
12729
|
+
{
|
|
12730
|
+
this.calendar = new LX.Calendar( dateValue, {
|
|
12731
|
+
onChange: ( date ) => {
|
|
12732
|
+
const newDateString = `${ date.day }/${ date.month }/${ date.year }`;
|
|
12733
|
+
this.set( newDateString );
|
|
12734
|
+
},
|
|
12735
|
+
...options
|
|
12736
|
+
});
|
|
12737
|
+
}
|
|
12738
|
+
else
|
|
12739
|
+
{
|
|
12740
|
+
this.calendar = new LX.CalendarRange( dateValue, {
|
|
12741
|
+
onChange: ( dateRange ) => {
|
|
12742
|
+
this.set( dateRange );
|
|
12743
|
+
},
|
|
12744
|
+
...options
|
|
12745
|
+
});
|
|
12746
|
+
}
|
|
12456
12747
|
|
|
12457
12748
|
const refresh = ( currentDate ) => {
|
|
12749
|
+
|
|
12750
|
+
const emptyDate = !!currentDate;
|
|
12751
|
+
|
|
12458
12752
|
container.innerHTML = "";
|
|
12753
|
+
|
|
12754
|
+
currentDate = currentDate ?? "Pick a date";
|
|
12755
|
+
|
|
12756
|
+
const dts = currentDate.split( " to " );
|
|
12757
|
+
const d0 = dateAsRange ? dts[ 0 ] : currentDate;
|
|
12758
|
+
|
|
12459
12759
|
const calendarIcon = LX.makeIcon( "Calendar" );
|
|
12460
|
-
const calendarButton = new LX.Button( null,
|
|
12760
|
+
const calendarButton = new LX.Button( null, d0, () => {
|
|
12461
12761
|
this._popover = new LX.Popover( calendarButton.root, [ this.calendar ] );
|
|
12462
|
-
|
|
12463
|
-
|
|
12762
|
+
if( dateAsRange )
|
|
12763
|
+
{
|
|
12764
|
+
Object.assign( this._popover.root.style, { display: "flex", width: "auto" } );
|
|
12765
|
+
}
|
|
12766
|
+
}, { buttonClass: `flex flex-row px-3 ${ emptyDate ? "" : "fg-tertiary" } justify-between` } );
|
|
12464
12767
|
calendarButton.root.querySelector( "button" ).appendChild( calendarIcon );
|
|
12768
|
+
calendarButton.root.style.width = "100%";
|
|
12465
12769
|
container.appendChild( calendarButton.root );
|
|
12770
|
+
|
|
12771
|
+
if( dateAsRange )
|
|
12772
|
+
{
|
|
12773
|
+
const arrowRightIcon = LX.makeIcon( "ArrowRight" );
|
|
12774
|
+
LX.makeContainer( ["32px", "auto"], "content-center", arrowRightIcon.innerHTML, container );
|
|
12775
|
+
|
|
12776
|
+
const d1 = dts[ 1 ];
|
|
12777
|
+
const calendarIcon = LX.makeIcon( "Calendar" );
|
|
12778
|
+
const calendarButton = new LX.Button( null, d1, () => {
|
|
12779
|
+
this._popover = new LX.Popover( calendarButton.root, [ this.calendar ] );
|
|
12780
|
+
if( dateAsRange )
|
|
12781
|
+
{
|
|
12782
|
+
Object.assign( this._popover.root.style, { display: "flex", width: "auto" } );
|
|
12783
|
+
}
|
|
12784
|
+
}, { buttonClass: `flex flex-row px-3 ${ emptyDate ? "" : "fg-tertiary" } justify-between` } );
|
|
12785
|
+
calendarButton.root.querySelector( "button" ).appendChild( calendarIcon );
|
|
12786
|
+
calendarButton.root.style.width = "100%";
|
|
12787
|
+
container.appendChild( calendarButton.root );
|
|
12788
|
+
}
|
|
12466
12789
|
};
|
|
12467
12790
|
|
|
12468
|
-
|
|
12791
|
+
if( dateValue )
|
|
12792
|
+
{
|
|
12793
|
+
refresh( this.calendar.getFullDate() );
|
|
12794
|
+
}
|
|
12795
|
+
else
|
|
12796
|
+
{
|
|
12797
|
+
refresh();
|
|
12798
|
+
}
|
|
12469
12799
|
|
|
12470
12800
|
LX.doAsync( this.onResize.bind( this ) );
|
|
12471
12801
|
}
|
|
@@ -12518,8 +12848,8 @@ class Map2D extends Widget {
|
|
|
12518
12848
|
}
|
|
12519
12849
|
}
|
|
12520
12850
|
|
|
12521
|
-
LX.Map2D = Map2D;
|
|
12522
|
-
|
|
12851
|
+
LX.Map2D = Map2D;
|
|
12852
|
+
|
|
12523
12853
|
// panel.js @jxarco
|
|
12524
12854
|
|
|
12525
12855
|
/**
|
|
@@ -13131,6 +13461,7 @@ class Panel {
|
|
|
13131
13461
|
* img: Path to image to show as button value
|
|
13132
13462
|
* title: Text to show in native Element title
|
|
13133
13463
|
* buttonClass: Class to add to the native button element
|
|
13464
|
+
* mustConfirm: User must confirm trigger in a popover
|
|
13134
13465
|
*/
|
|
13135
13466
|
|
|
13136
13467
|
addButton( name, value, callback, options = {} ) {
|
|
@@ -13676,7 +14007,7 @@ class Panel {
|
|
|
13676
14007
|
/**
|
|
13677
14008
|
* @method addDate
|
|
13678
14009
|
* @param {String} name Widget name
|
|
13679
|
-
* @param {String}
|
|
14010
|
+
* @param {String} dateValue
|
|
13680
14011
|
* @param {Function} callback
|
|
13681
14012
|
* @param {Object} options:
|
|
13682
14013
|
* hideName: Don't use name as label [false]
|
|
@@ -13685,8 +14016,8 @@ class Panel {
|
|
|
13685
14016
|
* fromToday: Allow dates only from current day
|
|
13686
14017
|
*/
|
|
13687
14018
|
|
|
13688
|
-
addDate( name,
|
|
13689
|
-
const widget = new LX.DatePicker( name,
|
|
14019
|
+
addDate( name, dateValue, callback, options = { } ) {
|
|
14020
|
+
const widget = new LX.DatePicker( name, dateValue, callback, options );
|
|
13690
14021
|
return this._attachWidget( widget );
|
|
13691
14022
|
}
|
|
13692
14023
|
|
|
@@ -13704,8 +14035,8 @@ class Panel {
|
|
|
13704
14035
|
}
|
|
13705
14036
|
}
|
|
13706
14037
|
|
|
13707
|
-
LX.Panel = Panel;
|
|
13708
|
-
|
|
14038
|
+
LX.Panel = Panel;
|
|
14039
|
+
|
|
13709
14040
|
// branch.js @jxarco
|
|
13710
14041
|
|
|
13711
14042
|
/**
|
|
@@ -13929,8 +14260,8 @@ class Branch {
|
|
|
13929
14260
|
}
|
|
13930
14261
|
}
|
|
13931
14262
|
}
|
|
13932
|
-
LX.Branch = Branch;
|
|
13933
|
-
|
|
14263
|
+
LX.Branch = Branch;
|
|
14264
|
+
|
|
13934
14265
|
// menubar.js @jxarco
|
|
13935
14266
|
|
|
13936
14267
|
/**
|
|
@@ -14244,8 +14575,8 @@ class Menubar {
|
|
|
14244
14575
|
}
|
|
14245
14576
|
}
|
|
14246
14577
|
}
|
|
14247
|
-
LX.Menubar = Menubar;
|
|
14248
|
-
|
|
14578
|
+
LX.Menubar = Menubar;
|
|
14579
|
+
|
|
14249
14580
|
// sidebar.js @jxarco
|
|
14250
14581
|
|
|
14251
14582
|
/**
|
|
@@ -14940,8 +15271,8 @@ class Sidebar {
|
|
|
14940
15271
|
}
|
|
14941
15272
|
}
|
|
14942
15273
|
}
|
|
14943
|
-
LX.Sidebar = Sidebar;
|
|
14944
|
-
|
|
15274
|
+
LX.Sidebar = Sidebar;
|
|
15275
|
+
|
|
14945
15276
|
// asset_view.js @jxarco
|
|
14946
15277
|
|
|
14947
15278
|
class AssetViewEvent {
|
|
@@ -15819,6 +16150,305 @@ class AssetView {
|
|
|
15819
16150
|
}
|
|
15820
16151
|
}
|
|
15821
16152
|
|
|
15822
|
-
LX.AssetView = AssetView;
|
|
15823
|
-
|
|
15824
|
-
|
|
16153
|
+
LX.AssetView = AssetView;
|
|
16154
|
+
|
|
16155
|
+
// tour.js @jxarco
|
|
16156
|
+
|
|
16157
|
+
class Tour {
|
|
16158
|
+
|
|
16159
|
+
static ACTIVE_TOURS = [];
|
|
16160
|
+
|
|
16161
|
+
/**
|
|
16162
|
+
* @constructor Tour
|
|
16163
|
+
* @param {Array} steps
|
|
16164
|
+
* @param {Object} options
|
|
16165
|
+
* useModal: Use a modal to highlight the tour step [true]
|
|
16166
|
+
* offset: Horizontal and vertical margin offset [0]
|
|
16167
|
+
* horizontalOffset: Horizontal offset [0]
|
|
16168
|
+
* verticalOffset: Vertical offset [0]
|
|
16169
|
+
* radius: Radius for the tour step highlight [8]
|
|
16170
|
+
*/
|
|
16171
|
+
|
|
16172
|
+
constructor( steps, options = {} ) {
|
|
16173
|
+
|
|
16174
|
+
this.steps = steps || [];
|
|
16175
|
+
this.currentStep = 0;
|
|
16176
|
+
|
|
16177
|
+
this.useModal = options.useModal ?? true;
|
|
16178
|
+
this.offset = options.offset ?? 8;
|
|
16179
|
+
this.horizontalOffset = options.horizontalOffset;
|
|
16180
|
+
this.verticalOffset = options.verticalOffset;
|
|
16181
|
+
this.radius = options.radius ?? 12;
|
|
16182
|
+
|
|
16183
|
+
this.tourContainer = document.querySelector( ".tour-container" );
|
|
16184
|
+
if( !this.tourContainer )
|
|
16185
|
+
{
|
|
16186
|
+
this.tourContainer = LX.makeContainer( ["100%", "100%"], "tour-container" );
|
|
16187
|
+
this.tourContainer.style.display = "none";
|
|
16188
|
+
document.body.appendChild( this.tourContainer );
|
|
16189
|
+
|
|
16190
|
+
window.addEventListener( "resize", () => {
|
|
16191
|
+
|
|
16192
|
+
for( const tour of Tour.ACTIVE_TOURS )
|
|
16193
|
+
{
|
|
16194
|
+
tour._showStep( 0 );
|
|
16195
|
+
}
|
|
16196
|
+
} );
|
|
16197
|
+
}
|
|
16198
|
+
}
|
|
16199
|
+
|
|
16200
|
+
/**
|
|
16201
|
+
* @method begin
|
|
16202
|
+
*/
|
|
16203
|
+
|
|
16204
|
+
begin() {
|
|
16205
|
+
|
|
16206
|
+
this.currentStep = 0;
|
|
16207
|
+
|
|
16208
|
+
this.tourContainer.style.display = "block";
|
|
16209
|
+
|
|
16210
|
+
Tour.ACTIVE_TOURS.push( this );
|
|
16211
|
+
|
|
16212
|
+
this._showStep( 0 );
|
|
16213
|
+
}
|
|
16214
|
+
|
|
16215
|
+
/**
|
|
16216
|
+
* @method stop
|
|
16217
|
+
*/
|
|
16218
|
+
|
|
16219
|
+
stop() {
|
|
16220
|
+
|
|
16221
|
+
if( this.useModal )
|
|
16222
|
+
{
|
|
16223
|
+
this.tourMask.remove();
|
|
16224
|
+
this.tourMask = undefined;
|
|
16225
|
+
}
|
|
16226
|
+
|
|
16227
|
+
this._popover?.destroy();
|
|
16228
|
+
|
|
16229
|
+
const index = Tour.ACTIVE_TOURS.indexOf( this );
|
|
16230
|
+
if( index !== -1 )
|
|
16231
|
+
{
|
|
16232
|
+
Tour.ACTIVE_TOURS.splice( index, 1 );
|
|
16233
|
+
}
|
|
16234
|
+
|
|
16235
|
+
this.tourContainer.innerHTML = "";
|
|
16236
|
+
this.tourContainer.style.display = "none";
|
|
16237
|
+
}
|
|
16238
|
+
|
|
16239
|
+
// Show the current step of the tour
|
|
16240
|
+
_showStep( stepOffset = 1 ) {
|
|
16241
|
+
|
|
16242
|
+
this.currentStep += stepOffset;
|
|
16243
|
+
|
|
16244
|
+
const step = this.steps[ this.currentStep ];
|
|
16245
|
+
if ( !step ) {
|
|
16246
|
+
this.stop();
|
|
16247
|
+
return;
|
|
16248
|
+
}
|
|
16249
|
+
|
|
16250
|
+
const prevStep = this.steps[ this.currentStep - 1 ];
|
|
16251
|
+
const nextStep = this.steps[ this.currentStep + 1 ];
|
|
16252
|
+
|
|
16253
|
+
if( this.useModal )
|
|
16254
|
+
{
|
|
16255
|
+
this._generateMask( step.reference );
|
|
16256
|
+
}
|
|
16257
|
+
|
|
16258
|
+
this._createHighlight( step, prevStep, nextStep );
|
|
16259
|
+
}
|
|
16260
|
+
|
|
16261
|
+
// Generate mask for the specific step reference
|
|
16262
|
+
// using a fullscreen SVG with "rect" elements
|
|
16263
|
+
_generateMask( reference ) {
|
|
16264
|
+
|
|
16265
|
+
this.tourContainer.innerHTML = ""; // Clear previous content
|
|
16266
|
+
|
|
16267
|
+
this.tourMask = LX.makeContainer( ["100%", "100%"], "tour-mask" );
|
|
16268
|
+
this.tourContainer.appendChild( this.tourMask );
|
|
16269
|
+
|
|
16270
|
+
const svg = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
|
|
16271
|
+
svg.style.width = "100%";
|
|
16272
|
+
svg.style.height = "100%";
|
|
16273
|
+
this.tourMask.appendChild( svg );
|
|
16274
|
+
|
|
16275
|
+
const clipPath = document.createElementNS( "http://www.w3.org/2000/svg", "clipPath" );
|
|
16276
|
+
clipPath.setAttribute( "id", "svgTourClipPath" );
|
|
16277
|
+
svg.appendChild( clipPath );
|
|
16278
|
+
|
|
16279
|
+
function ceilAndShiftRect( p, s ) {
|
|
16280
|
+
const cp = Math.ceil( p );
|
|
16281
|
+
const delta = cp - p;
|
|
16282
|
+
const ds = s - delta;
|
|
16283
|
+
return [ cp, ds ];
|
|
16284
|
+
}
|
|
16285
|
+
|
|
16286
|
+
const refBounding = reference.getBoundingClientRect();
|
|
16287
|
+
const [ boundingX, boundingWidth ] = ceilAndShiftRect( refBounding.x, refBounding.width );
|
|
16288
|
+
const [ boundingY, boundingHeight ] = ceilAndShiftRect( refBounding.y, refBounding.height );
|
|
16289
|
+
|
|
16290
|
+
const vOffset = this.verticalOffset ?? this.offset;
|
|
16291
|
+
const hOffset = this.horizontalOffset ?? this.offset;
|
|
16292
|
+
|
|
16293
|
+
// Left
|
|
16294
|
+
{
|
|
16295
|
+
const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16296
|
+
rect.setAttribute( "x", 0 );
|
|
16297
|
+
rect.setAttribute( "y", 0 );
|
|
16298
|
+
rect.setAttribute( "width", Math.max( 0, boundingX - hOffset ) );
|
|
16299
|
+
rect.setAttribute( "height", window.innerHeight );
|
|
16300
|
+
rect.setAttribute( "stroke", "none" );
|
|
16301
|
+
clipPath.appendChild( rect );
|
|
16302
|
+
}
|
|
16303
|
+
|
|
16304
|
+
// Top
|
|
16305
|
+
{
|
|
16306
|
+
const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16307
|
+
rect.setAttribute( "x", boundingX - hOffset );
|
|
16308
|
+
rect.setAttribute( "y", 0 );
|
|
16309
|
+
rect.setAttribute( "width", Math.max( 0, boundingWidth + hOffset * 2 ) );
|
|
16310
|
+
rect.setAttribute( "height", Math.max( 0, boundingY - vOffset ) );
|
|
16311
|
+
rect.setAttribute( "stroke", "none" );
|
|
16312
|
+
clipPath.appendChild( rect );
|
|
16313
|
+
}
|
|
16314
|
+
|
|
16315
|
+
// Bottom
|
|
16316
|
+
{
|
|
16317
|
+
const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16318
|
+
rect.setAttribute( "x", boundingX - hOffset );
|
|
16319
|
+
rect.setAttribute( "y", boundingY + boundingHeight + vOffset );
|
|
16320
|
+
rect.setAttribute( "width", Math.max( 0, boundingWidth + hOffset * 2 ) );
|
|
16321
|
+
rect.setAttribute( "height", Math.max( 0, window.innerHeight - boundingY - boundingHeight - vOffset ) );
|
|
16322
|
+
rect.setAttribute( "stroke", "none" );
|
|
16323
|
+
clipPath.appendChild( rect );
|
|
16324
|
+
}
|
|
16325
|
+
|
|
16326
|
+
// Right
|
|
16327
|
+
{
|
|
16328
|
+
const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16329
|
+
rect.setAttribute( "x", boundingX + boundingWidth + hOffset );
|
|
16330
|
+
rect.setAttribute( "y", 0 );
|
|
16331
|
+
rect.setAttribute( "width", Math.max( 0, window.innerWidth - boundingX - boundingWidth ) );
|
|
16332
|
+
rect.setAttribute( "height", Math.max( 0, window.innerHeight ) );
|
|
16333
|
+
rect.setAttribute( "stroke", "none" );
|
|
16334
|
+
clipPath.appendChild( rect );
|
|
16335
|
+
}
|
|
16336
|
+
|
|
16337
|
+
// Reference Highlight
|
|
16338
|
+
const refContainer = LX.makeContainer( ["0", "0"], "tour-ref-mask" );
|
|
16339
|
+
refContainer.style.left = `${ boundingX - hOffset - 1 }px`;
|
|
16340
|
+
refContainer.style.top = `${ boundingY - vOffset - 1 }px`;
|
|
16341
|
+
refContainer.style.width = `${ boundingWidth + hOffset * 2 + 2 }px`;
|
|
16342
|
+
refContainer.style.height = `${ boundingHeight + vOffset * 2 + 2}px`;
|
|
16343
|
+
this.tourContainer.appendChild( refContainer );
|
|
16344
|
+
|
|
16345
|
+
const referenceMask = document.createElementNS( "http://www.w3.org/2000/svg", "mask" );
|
|
16346
|
+
referenceMask.setAttribute( "id", "svgTourReferenceMask" );
|
|
16347
|
+
svg.appendChild( referenceMask );
|
|
16348
|
+
|
|
16349
|
+
// Reference Mask
|
|
16350
|
+
{
|
|
16351
|
+
const rectWhite = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16352
|
+
rectWhite.setAttribute( "width", boundingWidth + hOffset * 2 + 2 );
|
|
16353
|
+
rectWhite.setAttribute( "height", boundingHeight + vOffset * 2 + 2);
|
|
16354
|
+
rectWhite.setAttribute( "stroke", "none" );
|
|
16355
|
+
rectWhite.setAttribute( "fill", "white" );
|
|
16356
|
+
referenceMask.appendChild( rectWhite );
|
|
16357
|
+
|
|
16358
|
+
const rectBlack = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16359
|
+
rectBlack.setAttribute( "rx", this.radius );
|
|
16360
|
+
rectBlack.setAttribute( "width", boundingWidth + hOffset * 2 + 2);
|
|
16361
|
+
rectBlack.setAttribute( "height", boundingHeight + vOffset * 2 + 2);
|
|
16362
|
+
rectBlack.setAttribute( "stroke", "none" );
|
|
16363
|
+
rectBlack.setAttribute( "fill", "black" );
|
|
16364
|
+
referenceMask.appendChild( rectBlack );
|
|
16365
|
+
}
|
|
16366
|
+
}
|
|
16367
|
+
|
|
16368
|
+
// Create the container with the user hints
|
|
16369
|
+
_createHighlight( step, previousStep, nextStep ) {
|
|
16370
|
+
|
|
16371
|
+
const popoverContainer = LX.makeContainer( ["auto", "auto"], "tour-step-container" );
|
|
16372
|
+
|
|
16373
|
+
{
|
|
16374
|
+
const header = LX.makeContainer( ["100%", "auto"], "flex flex-row", "", popoverContainer );
|
|
16375
|
+
LX.makeContainer( ["70%", "auto"], "p-2 font-medium", step.title, header );
|
|
16376
|
+
const closer = LX.makeContainer( ["30%", "auto"], "flex flex-row p-2 justify-end", "", header );
|
|
16377
|
+
const closeIcon = LX.makeIcon( "X" );
|
|
16378
|
+
closer.appendChild( closeIcon );
|
|
16379
|
+
|
|
16380
|
+
closeIcon.listen( "click", () => {
|
|
16381
|
+
this.stop();
|
|
16382
|
+
} );
|
|
16383
|
+
}
|
|
16384
|
+
|
|
16385
|
+
LX.makeContainer( ["100%", "auto"], "p-2 text-md", step.content, popoverContainer, { maxWidth: "400px" } );
|
|
16386
|
+
const footer = LX.makeContainer( ["100%", "auto"], "flex flex-row text-md", "", popoverContainer );
|
|
16387
|
+
|
|
16388
|
+
{
|
|
16389
|
+
const footerSteps = LX.makeContainer( ["50%", "auto"], "p-2 gap-1 self-center flex flex-row text-md", "", footer );
|
|
16390
|
+
for( let i = 0; i < this.steps.length; i++ )
|
|
16391
|
+
{
|
|
16392
|
+
const stepIndicator = document.createElement( "span" );
|
|
16393
|
+
stepIndicator.className = "tour-step-indicator";
|
|
16394
|
+
if( i === this.currentStep )
|
|
16395
|
+
{
|
|
16396
|
+
stepIndicator.classList.add( "active" );
|
|
16397
|
+
}
|
|
16398
|
+
footerSteps.appendChild( stepIndicator );
|
|
16399
|
+
}
|
|
16400
|
+
}
|
|
16401
|
+
|
|
16402
|
+
const footerButtons = LX.makeContainer( ["50%", "auto"], "text-md", "", footer );
|
|
16403
|
+
const footerPanel = new LX.Panel();
|
|
16404
|
+
|
|
16405
|
+
let numButtons = 1;
|
|
16406
|
+
|
|
16407
|
+
if( previousStep )
|
|
16408
|
+
{
|
|
16409
|
+
numButtons++;
|
|
16410
|
+
}
|
|
16411
|
+
|
|
16412
|
+
if( numButtons > 1 )
|
|
16413
|
+
{
|
|
16414
|
+
footerPanel.sameLine( 2, "justify-end" );
|
|
16415
|
+
}
|
|
16416
|
+
|
|
16417
|
+
if( previousStep )
|
|
16418
|
+
{
|
|
16419
|
+
footerPanel.addButton( null, "Previous", () => {
|
|
16420
|
+
this._showStep( -1 );
|
|
16421
|
+
}, { buttonClass: "contrast" } );
|
|
16422
|
+
}
|
|
16423
|
+
|
|
16424
|
+
if( nextStep )
|
|
16425
|
+
{
|
|
16426
|
+
footerPanel.addButton( null, "Next", () => {
|
|
16427
|
+
this._showStep( 1 );
|
|
16428
|
+
}, { buttonClass: "accent" } );
|
|
16429
|
+
}
|
|
16430
|
+
else
|
|
16431
|
+
{
|
|
16432
|
+
footerPanel.addButton( null, "Finish", () => {
|
|
16433
|
+
this.stop();
|
|
16434
|
+
} );
|
|
16435
|
+
}
|
|
16436
|
+
|
|
16437
|
+
footerButtons.appendChild( footerPanel.root );
|
|
16438
|
+
|
|
16439
|
+
const sideOffset = ( step.side === "left" || step.side === "right" ? this.horizontalOffset : this.verticalOffset ) ?? this.offset;
|
|
16440
|
+
const alignOffset = ( step.align === "start" || step.align === "end" ? sideOffset : 0 );
|
|
16441
|
+
|
|
16442
|
+
this._popover?.destroy();
|
|
16443
|
+
this._popover = new LX.Popover( null, [ popoverContainer ], {
|
|
16444
|
+
reference: step.reference,
|
|
16445
|
+
side: step.side,
|
|
16446
|
+
align: step.align,
|
|
16447
|
+
sideOffset,
|
|
16448
|
+
alignOffset: step.align === "start" ? -alignOffset : alignOffset,
|
|
16449
|
+
} );
|
|
16450
|
+
}
|
|
16451
|
+
}
|
|
16452
|
+
LX.Tour = Tour;
|
|
16453
|
+
|
|
16454
|
+
export { ADD_CUSTOM_WIDGET, Area, AssetView, AssetViewEvent, Branch, LX, Menubar, Panel, Sidebar, Tour, Widget };
|