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.js
CHANGED
|
@@ -14,7 +14,7 @@ console.warn( 'Script _build/lexgui.js_ is depracated and will be removed soon.
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
const LX = {
|
|
17
|
-
version: "0.6.
|
|
17
|
+
version: "0.6.12",
|
|
18
18
|
ready: false,
|
|
19
19
|
components: [], // Specific pre-build components
|
|
20
20
|
signals: {}, // Events and triggers
|
|
@@ -725,8 +725,6 @@ class Popover {
|
|
|
725
725
|
|
|
726
726
|
constructor( trigger, content, options = {} ) {
|
|
727
727
|
|
|
728
|
-
console.assert( trigger, "Popover needs a DOM element as trigger!" );
|
|
729
|
-
|
|
730
728
|
if( Popover.activeElement )
|
|
731
729
|
{
|
|
732
730
|
Popover.activeElement.destroy();
|
|
@@ -734,13 +732,20 @@ class Popover {
|
|
|
734
732
|
}
|
|
735
733
|
|
|
736
734
|
this._trigger = trigger;
|
|
737
|
-
|
|
738
|
-
trigger
|
|
735
|
+
|
|
736
|
+
if( trigger )
|
|
737
|
+
{
|
|
738
|
+
trigger.classList.add( "triggered" );
|
|
739
|
+
trigger.active = this;
|
|
740
|
+
}
|
|
739
741
|
|
|
740
742
|
this._windowPadding = 4;
|
|
741
743
|
this.side = options.side ?? "bottom";
|
|
742
744
|
this.align = options.align ?? "center";
|
|
745
|
+
this.sideOffset = options.sideOffset ?? 0;
|
|
746
|
+
this.alignOffset = options.alignOffset ?? 0;
|
|
743
747
|
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
748
|
+
this.reference = options.reference;
|
|
744
749
|
|
|
745
750
|
this.root = document.createElement( "div" );
|
|
746
751
|
this.root.dataset["side"] = this.side;
|
|
@@ -775,29 +780,35 @@ class Popover {
|
|
|
775
780
|
LX.doAsync( () => {
|
|
776
781
|
this._adjustPosition();
|
|
777
782
|
|
|
778
|
-
this.
|
|
783
|
+
if( this._trigger )
|
|
784
|
+
{
|
|
785
|
+
this.root.focus();
|
|
779
786
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
+
this._onClick = e => {
|
|
788
|
+
if( e.target && ( this.root.contains( e.target ) || e.target == this._trigger ) )
|
|
789
|
+
{
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
this.destroy();
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
796
|
+
document.body.addEventListener( "focusin", this._onClick, true );
|
|
797
|
+
}
|
|
787
798
|
|
|
788
|
-
document.body.addEventListener( "mousedown", this._onClick, true );
|
|
789
|
-
document.body.addEventListener( "focusin", this._onClick, true );
|
|
790
799
|
}, 10 );
|
|
791
800
|
}
|
|
792
801
|
|
|
793
802
|
destroy() {
|
|
794
803
|
|
|
795
|
-
this._trigger
|
|
796
|
-
|
|
797
|
-
|
|
804
|
+
if( this._trigger )
|
|
805
|
+
{
|
|
806
|
+
this._trigger.classList.remove( "triggered" );
|
|
807
|
+
delete this._trigger.active;
|
|
798
808
|
|
|
799
|
-
|
|
800
|
-
|
|
809
|
+
document.body.removeEventListener( "mousedown", this._onClick, true );
|
|
810
|
+
document.body.removeEventListener( "focusin", this._onClick, true );
|
|
811
|
+
}
|
|
801
812
|
|
|
802
813
|
this.root.remove();
|
|
803
814
|
|
|
@@ -810,26 +821,28 @@ class Popover {
|
|
|
810
821
|
|
|
811
822
|
// Place menu using trigger position and user options
|
|
812
823
|
{
|
|
813
|
-
const
|
|
824
|
+
const el = this.reference ?? this._trigger;
|
|
825
|
+
console.assert( el, "Popover needs a trigger or reference element!" );
|
|
826
|
+
const rect = el.getBoundingClientRect();
|
|
814
827
|
|
|
815
828
|
let alignWidth = true;
|
|
816
829
|
|
|
817
830
|
switch( this.side )
|
|
818
831
|
{
|
|
819
832
|
case "left":
|
|
820
|
-
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
833
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth - this.sideOffset );
|
|
821
834
|
alignWidth = false;
|
|
822
835
|
break;
|
|
823
836
|
case "right":
|
|
824
|
-
position[ 0 ] += ( rect.x + rect.width );
|
|
837
|
+
position[ 0 ] += ( rect.x + rect.width + this.sideOffset );
|
|
825
838
|
alignWidth = false;
|
|
826
839
|
break;
|
|
827
840
|
case "top":
|
|
828
|
-
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
841
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight - this.sideOffset );
|
|
829
842
|
alignWidth = true;
|
|
830
843
|
break;
|
|
831
844
|
case "bottom":
|
|
832
|
-
position[ 1 ] += ( rect.y + rect.height );
|
|
845
|
+
position[ 1 ] += ( rect.y + rect.height + this.sideOffset );
|
|
833
846
|
alignWidth = true;
|
|
834
847
|
break;
|
|
835
848
|
}
|
|
@@ -849,6 +862,9 @@ class Popover {
|
|
|
849
862
|
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
850
863
|
break;
|
|
851
864
|
}
|
|
865
|
+
|
|
866
|
+
if( alignWidth ) { position[ 0 ] += this.alignOffset; }
|
|
867
|
+
else { position[ 1 ] += this.alignOffset; }
|
|
852
868
|
}
|
|
853
869
|
|
|
854
870
|
if( this.avoidCollisions )
|
|
@@ -863,6 +879,58 @@ class Popover {
|
|
|
863
879
|
}
|
|
864
880
|
LX.Popover = Popover;
|
|
865
881
|
|
|
882
|
+
/**
|
|
883
|
+
* @class PopConfirm
|
|
884
|
+
*/
|
|
885
|
+
|
|
886
|
+
class PopConfirm {
|
|
887
|
+
|
|
888
|
+
constructor( reference, options = {} ) {
|
|
889
|
+
|
|
890
|
+
const okText = options.confirmText ?? "Yes";
|
|
891
|
+
const cancelText = options.cancelText ?? "No";
|
|
892
|
+
const title = options.title ?? "Confirm";
|
|
893
|
+
const content = options.content ?? "Are you sure you want to proceed?";
|
|
894
|
+
const onConfirm = options.onConfirm;
|
|
895
|
+
const onCancel = options.onCancel;
|
|
896
|
+
|
|
897
|
+
const popoverContainer = LX.makeContainer( ["auto", "auto"], "tour-step-container" );
|
|
898
|
+
|
|
899
|
+
{
|
|
900
|
+
const headerDiv = LX.makeContainer( ["100%", "auto"], "flex flex-row", "", popoverContainer );
|
|
901
|
+
LX.makeContainer( ["100%", "auto"], "p-1 font-medium text-md", title, headerDiv );
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
LX.makeContainer( ["100%", "auto"], "p-1 text-md", content, popoverContainer, { maxWidth: "400px" } );
|
|
905
|
+
const footer = LX.makeContainer( ["100%", "auto"], "flex flex-row text-md", "", popoverContainer );
|
|
906
|
+
const footerButtons = LX.makeContainer( ["100%", "auto"], "text-md", "", footer );
|
|
907
|
+
const footerPanel = new LX.Panel();
|
|
908
|
+
footerButtons.appendChild( footerPanel.root );
|
|
909
|
+
|
|
910
|
+
footerPanel.sameLine( 2, "justify-end" );
|
|
911
|
+
footerPanel.addButton( null, cancelText, () => {
|
|
912
|
+
if( onCancel ) onCancel();
|
|
913
|
+
this._popover?.destroy();
|
|
914
|
+
}, { xbuttonClass: "contrast" } );
|
|
915
|
+
footerPanel.addButton( null, okText, () => {
|
|
916
|
+
if( onConfirm ) onConfirm();
|
|
917
|
+
this._popover?.destroy();
|
|
918
|
+
}, { buttonClass: "accent" } );
|
|
919
|
+
|
|
920
|
+
this._popover?.destroy();
|
|
921
|
+
this._popover = new LX.Popover( null, [ popoverContainer ], {
|
|
922
|
+
reference,
|
|
923
|
+
side: options.side ?? "top",
|
|
924
|
+
align: options.align,
|
|
925
|
+
sideOffset: options.sideOffset,
|
|
926
|
+
alignOffset: options.alignOffset,
|
|
927
|
+
} );
|
|
928
|
+
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
LX.PopConfirm = PopConfirm;
|
|
933
|
+
|
|
866
934
|
/**
|
|
867
935
|
* @class Sheet
|
|
868
936
|
*/
|
|
@@ -985,6 +1053,8 @@ class DropdownMenu {
|
|
|
985
1053
|
this._windowPadding = 4;
|
|
986
1054
|
this.side = options.side ?? "bottom";
|
|
987
1055
|
this.align = options.align ?? "center";
|
|
1056
|
+
this.sideOffset = options.sideOffset ?? 0;
|
|
1057
|
+
this.alignOffset = options.alignOffset ?? 0;
|
|
988
1058
|
this.avoidCollisions = options.avoidCollisions ?? true;
|
|
989
1059
|
this.onBlur = options.onBlur;
|
|
990
1060
|
this.inPlace = false;
|
|
@@ -1227,19 +1297,19 @@ class DropdownMenu {
|
|
|
1227
1297
|
switch( this.side )
|
|
1228
1298
|
{
|
|
1229
1299
|
case "left":
|
|
1230
|
-
position[ 0 ] += ( rect.x - this.root.offsetWidth );
|
|
1300
|
+
position[ 0 ] += ( rect.x - this.root.offsetWidth - this.sideOffset );
|
|
1231
1301
|
alignWidth = false;
|
|
1232
1302
|
break;
|
|
1233
1303
|
case "right":
|
|
1234
|
-
position[ 0 ] += ( rect.x + rect.width );
|
|
1304
|
+
position[ 0 ] += ( rect.x + rect.width + this.sideOffset );
|
|
1235
1305
|
alignWidth = false;
|
|
1236
1306
|
break;
|
|
1237
1307
|
case "top":
|
|
1238
|
-
position[ 1 ] += ( rect.y - this.root.offsetHeight );
|
|
1308
|
+
position[ 1 ] += ( rect.y - this.root.offsetHeight - this.sideOffset );
|
|
1239
1309
|
alignWidth = true;
|
|
1240
1310
|
break;
|
|
1241
1311
|
case "bottom":
|
|
1242
|
-
position[ 1 ] += ( rect.y + rect.height );
|
|
1312
|
+
position[ 1 ] += ( rect.y + rect.height + this.sideOffset );
|
|
1243
1313
|
alignWidth = true;
|
|
1244
1314
|
break;
|
|
1245
1315
|
}
|
|
@@ -1259,6 +1329,9 @@ class DropdownMenu {
|
|
|
1259
1329
|
else { position[ 1 ] += rect.y - this.root.offsetHeight + rect.height; }
|
|
1260
1330
|
break;
|
|
1261
1331
|
}
|
|
1332
|
+
|
|
1333
|
+
if( alignWidth ) { position[ 0 ] += this.alignOffset; }
|
|
1334
|
+
else { position[ 1 ] += this.alignOffset; }
|
|
1262
1335
|
}
|
|
1263
1336
|
|
|
1264
1337
|
if( this.avoidCollisions )
|
|
@@ -1653,8 +1726,15 @@ class Calendar {
|
|
|
1653
1726
|
this.root = LX.makeContainer( ["256px", "auto"], "p-1 text-md" );
|
|
1654
1727
|
|
|
1655
1728
|
this.onChange = options.onChange;
|
|
1729
|
+
this.onPreviousMonth = options.onPreviousMonth;
|
|
1730
|
+
this.onNextMonth = options.onNextMonth;
|
|
1731
|
+
|
|
1656
1732
|
this.untilToday = options.untilToday;
|
|
1657
1733
|
this.fromToday = options.fromToday;
|
|
1734
|
+
this.range = options.range;
|
|
1735
|
+
|
|
1736
|
+
this.skipPrevMonth = options.skipPrevMonth;
|
|
1737
|
+
this.skipNextMonth = options.skipNextMonth;
|
|
1658
1738
|
|
|
1659
1739
|
if( dateString )
|
|
1660
1740
|
{
|
|
@@ -1678,7 +1758,7 @@ class Calendar {
|
|
|
1678
1758
|
}
|
|
1679
1759
|
}
|
|
1680
1760
|
|
|
1681
|
-
_previousMonth() {
|
|
1761
|
+
_previousMonth( skipCallback ) {
|
|
1682
1762
|
|
|
1683
1763
|
this.month = Math.max( 0, this.month - 1 );
|
|
1684
1764
|
|
|
@@ -1689,9 +1769,14 @@ class Calendar {
|
|
|
1689
1769
|
}
|
|
1690
1770
|
|
|
1691
1771
|
this.fromMonthYear( this.month, this.year );
|
|
1772
|
+
|
|
1773
|
+
if( !skipCallback && this.onPreviousMonth )
|
|
1774
|
+
{
|
|
1775
|
+
this.onPreviousMonth( this.currentDate );
|
|
1776
|
+
}
|
|
1692
1777
|
}
|
|
1693
1778
|
|
|
1694
|
-
_nextMonth() {
|
|
1779
|
+
_nextMonth( skipCallback ) {
|
|
1695
1780
|
|
|
1696
1781
|
this.month = Math.min( this.month + 1, 12 );
|
|
1697
1782
|
|
|
@@ -1702,6 +1787,11 @@ class Calendar {
|
|
|
1702
1787
|
}
|
|
1703
1788
|
|
|
1704
1789
|
this.fromMonthYear( this.month, this.year );
|
|
1790
|
+
|
|
1791
|
+
if( !skipCallback && this.onNextMonth )
|
|
1792
|
+
{
|
|
1793
|
+
this.onNextMonth( this.currentDate );
|
|
1794
|
+
}
|
|
1705
1795
|
}
|
|
1706
1796
|
|
|
1707
1797
|
refresh() {
|
|
@@ -1712,19 +1802,25 @@ class Calendar {
|
|
|
1712
1802
|
{
|
|
1713
1803
|
const header = LX.makeContainer( ["100%", "auto"], "flex flex-row p-1", "", this.root );
|
|
1714
1804
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1805
|
+
if( !this.skipPrevMonth )
|
|
1806
|
+
{
|
|
1807
|
+
const prevMonthIcon = LX.makeIcon( "Left", { title: "Previous Month", iconClass: "border p-1 rounded hover:bg-secondary", svgClass: "sm" } );
|
|
1808
|
+
header.appendChild( prevMonthIcon );
|
|
1809
|
+
prevMonthIcon.addEventListener( "click", () => {
|
|
1810
|
+
this._previousMonth();
|
|
1811
|
+
} );
|
|
1812
|
+
}
|
|
1720
1813
|
|
|
1721
1814
|
LX.makeContainer( ["100%", "auto"], "text-center font-medium select-none", `${ this.monthName } ${ this.year }`, header );
|
|
1722
1815
|
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1816
|
+
if( !this.skipNextMonth )
|
|
1817
|
+
{
|
|
1818
|
+
const nextMonthIcon = LX.makeIcon( "Right", { title: "Next Month", iconClass: "border p-1 rounded hover:bg-secondary", svgClass: "sm" } );
|
|
1819
|
+
header.appendChild( nextMonthIcon );
|
|
1820
|
+
nextMonthIcon.addEventListener( "click", () => {
|
|
1821
|
+
this._nextMonth();
|
|
1822
|
+
} );
|
|
1823
|
+
}
|
|
1728
1824
|
}
|
|
1729
1825
|
|
|
1730
1826
|
// Body
|
|
@@ -1756,6 +1852,11 @@ class Calendar {
|
|
|
1756
1852
|
const body = document.createElement( 'tbody' );
|
|
1757
1853
|
daysTable.appendChild( body );
|
|
1758
1854
|
|
|
1855
|
+
let fromRangeDate = this.range ? LX.dateFromDateString( this.range[ 0 ] ) : null;
|
|
1856
|
+
let toRangeDate = this.range ? LX.dateFromDateString( this.range[ 1 ] ) : null;
|
|
1857
|
+
|
|
1858
|
+
this.currentDate ? new Date( `${ this.currentDate.month }/${ this.currentDate.day }/${ this.currentDate.year }` ) : null;
|
|
1859
|
+
|
|
1759
1860
|
for( let week = 0; week < 6; week++ )
|
|
1760
1861
|
{
|
|
1761
1862
|
const hrow = document.createElement( 'tr' );
|
|
@@ -1768,15 +1869,28 @@ class Calendar {
|
|
|
1768
1869
|
|
|
1769
1870
|
const dayDate = new Date( `${ this.month }/${ dayData.day }/${ this.year }` );
|
|
1770
1871
|
const date = new Date();
|
|
1872
|
+
// today inclusives
|
|
1771
1873
|
const beforeToday = this.untilToday ? ( dayDate.getTime() < date.getTime() ) : true;
|
|
1772
|
-
const afterToday = this.fromToday ? ( dayDate.
|
|
1874
|
+
const afterToday = this.fromToday ? ( dayDate.getFullYear() > date.getFullYear() ||
|
|
1875
|
+
(dayDate.getFullYear() === date.getFullYear() && dayDate.getMonth() > date.getMonth()) ||
|
|
1876
|
+
(dayDate.getFullYear() === date.getFullYear() && dayDate.getMonth() === date.getMonth() && dayDate.getDate() >= date.getDate())
|
|
1877
|
+
) : true;
|
|
1773
1878
|
const selectable = dayData.currentMonth && beforeToday && afterToday;
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1879
|
+
const currentDay = this.currentDate && ( dayData.day == this.currentDate.day ) && ( this.month == this.currentDate.month )
|
|
1880
|
+
&& ( this.year == this.currentDate.year ) && dayData.currentMonth;
|
|
1881
|
+
const currentFromRange = selectable && fromRangeDate && ( dayData.day == fromRangeDate.getDate() ) && ( this.month == ( fromRangeDate.getMonth() + 1 ) )
|
|
1882
|
+
&& ( this.year == fromRangeDate.getFullYear() );
|
|
1883
|
+
const currentToRange = selectable && toRangeDate && ( dayData.day == toRangeDate.getDate() ) && ( this.month == ( toRangeDate.getMonth() + 1 ) )
|
|
1884
|
+
&& ( this.year == toRangeDate.getFullYear() );
|
|
1885
|
+
|
|
1886
|
+
if( ( !this.range && currentDay ) || this.range && ( currentFromRange || currentToRange ) )
|
|
1777
1887
|
{
|
|
1778
1888
|
th.className += ` bg-contrast fg-contrast`;
|
|
1779
1889
|
}
|
|
1890
|
+
else if( this.range && selectable && ( dayDate > fromRangeDate ) && ( dayDate < toRangeDate ) )
|
|
1891
|
+
{
|
|
1892
|
+
th.className += ` bg-accent fg-contrast`;
|
|
1893
|
+
}
|
|
1780
1894
|
else
|
|
1781
1895
|
{
|
|
1782
1896
|
th.className += ` ${ selectable ? "fg-primary" : "fg-tertiary" } hover:bg-secondary`;
|
|
@@ -1796,6 +1910,20 @@ class Calendar {
|
|
|
1796
1910
|
}
|
|
1797
1911
|
} );
|
|
1798
1912
|
}
|
|
1913
|
+
// This event should only be applied in non current month days
|
|
1914
|
+
else if( this.range === undefined && !dayData.currentMonth )
|
|
1915
|
+
{
|
|
1916
|
+
th.addEventListener( "click", () => {
|
|
1917
|
+
if( dayData?.prevMonth )
|
|
1918
|
+
{
|
|
1919
|
+
this._previousMonth();
|
|
1920
|
+
}
|
|
1921
|
+
else
|
|
1922
|
+
{
|
|
1923
|
+
this._nextMonth();
|
|
1924
|
+
}
|
|
1925
|
+
} );
|
|
1926
|
+
}
|
|
1799
1927
|
}
|
|
1800
1928
|
|
|
1801
1929
|
body.appendChild( hrow );
|
|
@@ -1810,6 +1938,7 @@ class Calendar {
|
|
|
1810
1938
|
|
|
1811
1939
|
this.day = parseInt( tokens[ 0 ] );
|
|
1812
1940
|
this.month = parseInt( tokens[ 1 ] );
|
|
1941
|
+
this.monthName = this.getMonthName( this.month - 1 );
|
|
1813
1942
|
this.year = parseInt( tokens[ 2 ] );
|
|
1814
1943
|
|
|
1815
1944
|
this.currentDate = this._getCurrentDate();
|
|
@@ -1839,7 +1968,7 @@ class Calendar {
|
|
|
1839
1968
|
// Fill in days from previous month
|
|
1840
1969
|
for( let i = firstDay - 1; i >= 0; i--)
|
|
1841
1970
|
{
|
|
1842
|
-
calendarDays.push( { day: daysInPrevMonth - i, currentMonth: false } );
|
|
1971
|
+
calendarDays.push( { day: daysInPrevMonth - i, currentMonth: false, prevMonth: true } );
|
|
1843
1972
|
}
|
|
1844
1973
|
|
|
1845
1974
|
// Fill in current month days
|
|
@@ -1852,7 +1981,7 @@ class Calendar {
|
|
|
1852
1981
|
const remaining = 42 - calendarDays.length;
|
|
1853
1982
|
for( let i = 1; i <= remaining; i++ )
|
|
1854
1983
|
{
|
|
1855
|
-
calendarDays.push( { day: i, currentMonth: false } );
|
|
1984
|
+
calendarDays.push( { day: i, currentMonth: false, nextMonth: true } );
|
|
1856
1985
|
}
|
|
1857
1986
|
|
|
1858
1987
|
this.monthName = this.getMonthName( month );
|
|
@@ -1868,8 +1997,14 @@ class Calendar {
|
|
|
1868
1997
|
return formatter.format( new Date( 2000, monthIndex, 1 ) );
|
|
1869
1998
|
}
|
|
1870
1999
|
|
|
1871
|
-
getFullDate() {
|
|
1872
|
-
return `${ this.monthName } ${ this.day }${ this._getOrdinalSuffix( this.day ) }, ${ this.year }`;
|
|
2000
|
+
getFullDate( monthName, day, year ) {
|
|
2001
|
+
return `${ monthName ?? this.monthName } ${ day ?? this.day }${ this._getOrdinalSuffix( day ?? this.day ) }, ${ year ?? this.year }`;
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
setRange( range ) {
|
|
2005
|
+
console.assert( range.constructor === Array, "Date Range must be in Array format" );
|
|
2006
|
+
this.range = range;
|
|
2007
|
+
this.refresh();
|
|
1873
2008
|
}
|
|
1874
2009
|
|
|
1875
2010
|
_getOrdinalSuffix( day ) {
|
|
@@ -1886,6 +2021,110 @@ class Calendar {
|
|
|
1886
2021
|
|
|
1887
2022
|
LX.Calendar = Calendar;
|
|
1888
2023
|
|
|
2024
|
+
class CalendarRange {
|
|
2025
|
+
|
|
2026
|
+
/**
|
|
2027
|
+
* @constructor CalendarRange
|
|
2028
|
+
* @param {Array} range ["DD/MM/YYYY", "DD/MM/YYYY"]
|
|
2029
|
+
* @param {Object} options
|
|
2030
|
+
*/
|
|
2031
|
+
|
|
2032
|
+
constructor( range, options = {} ) {
|
|
2033
|
+
|
|
2034
|
+
this.root = LX.makeContainer( ["auto", "auto"], "flex flex-row" );
|
|
2035
|
+
|
|
2036
|
+
console.assert( range && range.constructor === Array, "Range cannot be empty and has to be an Array!" );
|
|
2037
|
+
|
|
2038
|
+
let mustAdvanceMonth = false;
|
|
2039
|
+
|
|
2040
|
+
// Fix any issues with date range picking
|
|
2041
|
+
{
|
|
2042
|
+
const t0 = LX.dateFromDateString( range[ 0 ] );
|
|
2043
|
+
const t1 = LX.dateFromDateString( range[ 1 ] );
|
|
2044
|
+
|
|
2045
|
+
if( t0 > t1 )
|
|
2046
|
+
{
|
|
2047
|
+
const tmp = range[ 0 ];
|
|
2048
|
+
range[ 0 ] = range[ 1 ];
|
|
2049
|
+
range[ 1 ] = tmp;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
mustAdvanceMonth = ( t0.getMonth() == t1.getMonth() ) && ( t0.getFullYear() == t1.getFullYear() );
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
this.from = range[ 0 ];
|
|
2056
|
+
this.to = range[ 1 ];
|
|
2057
|
+
|
|
2058
|
+
this._selectingRange = false;
|
|
2059
|
+
|
|
2060
|
+
const onChange = ( date ) => {
|
|
2061
|
+
|
|
2062
|
+
const newDateString = `${ date.day }/${ date.month }/${ date.year }`;
|
|
2063
|
+
|
|
2064
|
+
if( !this._selectingRange )
|
|
2065
|
+
{
|
|
2066
|
+
this.from = this.to = newDateString;
|
|
2067
|
+
this._selectingRange = true;
|
|
2068
|
+
}
|
|
2069
|
+
else
|
|
2070
|
+
{
|
|
2071
|
+
this.to = newDateString;
|
|
2072
|
+
this._selectingRange = false;
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
const newRange = [ this.from, this.to ];
|
|
2076
|
+
|
|
2077
|
+
this.fromCalendar.setRange( newRange );
|
|
2078
|
+
this.toCalendar.setRange( newRange );
|
|
2079
|
+
|
|
2080
|
+
if( options.onChange )
|
|
2081
|
+
{
|
|
2082
|
+
options.onChange( newRange );
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
};
|
|
2086
|
+
|
|
2087
|
+
this.fromCalendar = new LX.Calendar( this.from, {
|
|
2088
|
+
skipNextMonth: true,
|
|
2089
|
+
onChange,
|
|
2090
|
+
onPreviousMonth: () => {
|
|
2091
|
+
this.toCalendar._previousMonth();
|
|
2092
|
+
},
|
|
2093
|
+
range
|
|
2094
|
+
});
|
|
2095
|
+
|
|
2096
|
+
this.toCalendar = new LX.Calendar( this.to, {
|
|
2097
|
+
skipPrevMonth: true,
|
|
2098
|
+
onChange,
|
|
2099
|
+
onNextMonth: () => {
|
|
2100
|
+
this.fromCalendar._nextMonth();
|
|
2101
|
+
},
|
|
2102
|
+
range
|
|
2103
|
+
});
|
|
2104
|
+
|
|
2105
|
+
if( mustAdvanceMonth )
|
|
2106
|
+
{
|
|
2107
|
+
this.toCalendar._nextMonth( true );
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
this.root.appendChild( this.fromCalendar.root );
|
|
2111
|
+
this.root.appendChild( this.toCalendar.root );
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
getFullDate() {
|
|
2115
|
+
|
|
2116
|
+
const d0 = LX.dateFromDateString( this.from );
|
|
2117
|
+
const d0Month = this.fromCalendar.getMonthName( d0.getMonth() );
|
|
2118
|
+
|
|
2119
|
+
const d1 = LX.dateFromDateString( this.to );
|
|
2120
|
+
const d1Month = this.toCalendar.getMonthName( d1.getMonth() );
|
|
2121
|
+
|
|
2122
|
+
return `${ this.fromCalendar.getFullDate( d0Month, d0.getDate(), d0.getFullYear() ) } to ${ this.toCalendar.getFullDate( d1Month, d1.getDate(), d1.getFullYear() ) }`;
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
LX.CalendarRange = CalendarRange;
|
|
2127
|
+
|
|
1889
2128
|
/**
|
|
1890
2129
|
* @class Tabs
|
|
1891
2130
|
*/
|
|
@@ -4736,6 +4975,22 @@ function hsvToRgb( hsv )
|
|
|
4736
4975
|
|
|
4737
4976
|
LX.hsvToRgb = hsvToRgb;
|
|
4738
4977
|
|
|
4978
|
+
/**
|
|
4979
|
+
* @method dateFromDateString
|
|
4980
|
+
* @description Get an instance of Date() from a Date in String format (DD/MM/YYYY)
|
|
4981
|
+
* @param {String} dateString
|
|
4982
|
+
*/
|
|
4983
|
+
function dateFromDateString( dateString )
|
|
4984
|
+
{
|
|
4985
|
+
const tokens = dateString.split( '/' );
|
|
4986
|
+
const day = parseInt( tokens[ 0 ] );
|
|
4987
|
+
const month = parseInt( tokens[ 1 ] );
|
|
4988
|
+
const year = parseInt( tokens[ 2 ] );
|
|
4989
|
+
return new Date( `${ month }/${ day }/${ year }` );
|
|
4990
|
+
}
|
|
4991
|
+
|
|
4992
|
+
LX.dateFromDateString = dateFromDateString;
|
|
4993
|
+
|
|
4739
4994
|
/**
|
|
4740
4995
|
* @method measureRealWidth
|
|
4741
4996
|
* @description Measure the pixel width of a text
|
|
@@ -8667,6 +8922,20 @@ class Button extends Widget {
|
|
|
8667
8922
|
{
|
|
8668
8923
|
wValue.querySelector( ".file-input" ).click();
|
|
8669
8924
|
}
|
|
8925
|
+
else if( options.mustConfirm )
|
|
8926
|
+
{
|
|
8927
|
+
new LX.PopConfirm( wValue, {
|
|
8928
|
+
onConfirm: () => {
|
|
8929
|
+
this._trigger( new LX.IEvent( name, value, e ), callback );
|
|
8930
|
+
},
|
|
8931
|
+
side: options.confirmSide,
|
|
8932
|
+
align: options.confirmAlign,
|
|
8933
|
+
confirmText: options.confirmText,
|
|
8934
|
+
cancelText: options.confirmCancelText,
|
|
8935
|
+
title: options.confirmTitle,
|
|
8936
|
+
content: options.confirmContent
|
|
8937
|
+
} );
|
|
8938
|
+
}
|
|
8670
8939
|
else
|
|
8671
8940
|
{
|
|
8672
8941
|
const swapInput = wValue.querySelector( "input" );
|
|
@@ -8962,16 +9231,17 @@ class Form extends Widget {
|
|
|
8962
9231
|
|
|
8963
9232
|
if( entryData.constructor != Object )
|
|
8964
9233
|
{
|
|
8965
|
-
|
|
9234
|
+
const oldValue = JSON.parse( JSON.stringify( entryData ) );
|
|
9235
|
+
entryData = { value: oldValue };
|
|
8966
9236
|
data[ entry ] = entryData;
|
|
8967
9237
|
}
|
|
8968
9238
|
|
|
8969
|
-
entryData.placeholder = entryData.placeholder ?? entry;
|
|
9239
|
+
entryData.placeholder = entryData.placeholder ?? ( entryData.label ?? `Enter ${ entry }` );
|
|
8970
9240
|
entryData.width = "100%";
|
|
8971
9241
|
|
|
8972
9242
|
if( !( options.skipLabels ?? false ) )
|
|
8973
9243
|
{
|
|
8974
|
-
const label = new LX.TextInput( null, entry, null, { disabled: true, inputClass: "formlabel nobg" } );
|
|
9244
|
+
const label = new LX.TextInput( null, entryData.label ?? entry, null, { disabled: true, inputClass: "formlabel nobg" } );
|
|
8975
9245
|
container.appendChild( label.root );
|
|
8976
9246
|
}
|
|
8977
9247
|
|
|
@@ -10666,15 +10936,15 @@ class Vector extends Widget {
|
|
|
10666
10936
|
|
|
10667
10937
|
for( let i = 0; i < vectorInputs.length; ++i )
|
|
10668
10938
|
{
|
|
10669
|
-
let
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
vectorInputs[ i ].value =
|
|
10939
|
+
let vecValue = newValue[ i ];
|
|
10940
|
+
vecValue = LX.clamp( vecValue, +vectorInputs[ i ].min, +vectorInputs[ i ].max );
|
|
10941
|
+
vecValue = LX.round( vecValue, options.precision ) ?? 0;
|
|
10942
|
+
vectorInputs[ i ].value = value[ i ] = vecValue;
|
|
10673
10943
|
}
|
|
10674
10944
|
|
|
10675
10945
|
if( !skipCallback )
|
|
10676
10946
|
{
|
|
10677
|
-
this._trigger( new LX.IEvent( name,
|
|
10947
|
+
this._trigger( new LX.IEvent( name, value, event ), callback );
|
|
10678
10948
|
}
|
|
10679
10949
|
};
|
|
10680
10950
|
|
|
@@ -11264,12 +11534,18 @@ class Progress extends Widget {
|
|
|
11264
11534
|
};
|
|
11265
11535
|
|
|
11266
11536
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
11537
|
+
newValue = LX.clamp( newValue, progress.min, progress.max );
|
|
11267
11538
|
this.root.querySelector("meter").value = newValue;
|
|
11268
11539
|
_updateColor();
|
|
11269
11540
|
if( this.root.querySelector("span") )
|
|
11270
11541
|
{
|
|
11271
11542
|
this.root.querySelector("span").innerText = newValue;
|
|
11272
11543
|
}
|
|
11544
|
+
|
|
11545
|
+
if( !skipCallback )
|
|
11546
|
+
{
|
|
11547
|
+
this._trigger( new LX.IEvent( name, newValue, event ), options.callback );
|
|
11548
|
+
}
|
|
11273
11549
|
};
|
|
11274
11550
|
|
|
11275
11551
|
this.onResize = ( rect ) => {
|
|
@@ -11353,11 +11629,6 @@ class Progress extends Widget {
|
|
|
11353
11629
|
const rect = progress.getBoundingClientRect();
|
|
11354
11630
|
const newValue = LX.round( LX.remapRange( e.offsetX - rect.x, 0, rect.width, progress.min, progress.max ) );
|
|
11355
11631
|
this.set( newValue, false, e );
|
|
11356
|
-
|
|
11357
|
-
if( options.callback )
|
|
11358
|
-
{
|
|
11359
|
-
options.callback( newValue, e );
|
|
11360
|
-
}
|
|
11361
11632
|
}
|
|
11362
11633
|
|
|
11363
11634
|
e.stopPropagation();
|
|
@@ -12420,25 +12691,30 @@ LX.Table = Table;
|
|
|
12420
12691
|
|
|
12421
12692
|
class DatePicker extends Widget {
|
|
12422
12693
|
|
|
12423
|
-
constructor( name,
|
|
12694
|
+
constructor( name, dateValue, callback, options = { } ) {
|
|
12424
12695
|
|
|
12425
12696
|
super( Widget.DATE, name, null, options );
|
|
12426
12697
|
|
|
12427
|
-
|
|
12698
|
+
const dateAsRange = ( dateValue?.constructor === Array );
|
|
12699
|
+
|
|
12700
|
+
if( !dateAsRange && options.today )
|
|
12428
12701
|
{
|
|
12429
12702
|
const date = new Date();
|
|
12430
|
-
|
|
12703
|
+
dateValue = `${ date.getDate() }/${ date.getMonth() + 1 }/${ date.getFullYear() }`;
|
|
12431
12704
|
}
|
|
12432
12705
|
|
|
12433
12706
|
this.onGetValue = () => {
|
|
12434
|
-
return
|
|
12707
|
+
return dateValue;
|
|
12435
12708
|
};
|
|
12436
12709
|
|
|
12437
12710
|
this.onSetValue = ( newValue, skipCallback, event ) => {
|
|
12438
12711
|
|
|
12439
|
-
|
|
12712
|
+
if( !dateAsRange )
|
|
12713
|
+
{
|
|
12714
|
+
this.calendar.fromDateString( newValue );
|
|
12715
|
+
}
|
|
12440
12716
|
|
|
12441
|
-
|
|
12717
|
+
dateValue = newValue;
|
|
12442
12718
|
|
|
12443
12719
|
refresh( this.calendar.getFullDate() );
|
|
12444
12720
|
|
|
@@ -12453,26 +12729,80 @@ class DatePicker extends Widget {
|
|
|
12453
12729
|
container.style.width = `calc( 100% - ${ realNameWidth })`;
|
|
12454
12730
|
};
|
|
12455
12731
|
|
|
12456
|
-
const container =
|
|
12457
|
-
container.className = "lexdate";
|
|
12732
|
+
const container = LX.makeContainer( [ "auto", "auto" ], "lexdate flex flex-row" );
|
|
12458
12733
|
this.root.appendChild( container );
|
|
12459
12734
|
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12735
|
+
if( !dateAsRange )
|
|
12736
|
+
{
|
|
12737
|
+
this.calendar = new LX.Calendar( dateValue, {
|
|
12738
|
+
onChange: ( date ) => {
|
|
12739
|
+
const newDateString = `${ date.day }/${ date.month }/${ date.year }`;
|
|
12740
|
+
this.set( newDateString );
|
|
12741
|
+
},
|
|
12742
|
+
...options
|
|
12743
|
+
});
|
|
12744
|
+
}
|
|
12745
|
+
else
|
|
12746
|
+
{
|
|
12747
|
+
this.calendar = new LX.CalendarRange( dateValue, {
|
|
12748
|
+
onChange: ( dateRange ) => {
|
|
12749
|
+
this.set( dateRange );
|
|
12750
|
+
},
|
|
12751
|
+
...options
|
|
12752
|
+
});
|
|
12753
|
+
}
|
|
12463
12754
|
|
|
12464
12755
|
const refresh = ( currentDate ) => {
|
|
12756
|
+
|
|
12757
|
+
const emptyDate = !!currentDate;
|
|
12758
|
+
|
|
12465
12759
|
container.innerHTML = "";
|
|
12760
|
+
|
|
12761
|
+
currentDate = currentDate ?? "Pick a date";
|
|
12762
|
+
|
|
12763
|
+
const dts = currentDate.split( " to " );
|
|
12764
|
+
const d0 = dateAsRange ? dts[ 0 ] : currentDate;
|
|
12765
|
+
|
|
12466
12766
|
const calendarIcon = LX.makeIcon( "Calendar" );
|
|
12467
|
-
const calendarButton = new LX.Button( null,
|
|
12767
|
+
const calendarButton = new LX.Button( null, d0, () => {
|
|
12468
12768
|
this._popover = new LX.Popover( calendarButton.root, [ this.calendar ] );
|
|
12469
|
-
|
|
12470
|
-
|
|
12769
|
+
if( dateAsRange )
|
|
12770
|
+
{
|
|
12771
|
+
Object.assign( this._popover.root.style, { display: "flex", width: "auto" } );
|
|
12772
|
+
}
|
|
12773
|
+
}, { buttonClass: `flex flex-row px-3 ${ emptyDate ? "" : "fg-tertiary" } justify-between` } );
|
|
12471
12774
|
calendarButton.root.querySelector( "button" ).appendChild( calendarIcon );
|
|
12775
|
+
calendarButton.root.style.width = "100%";
|
|
12472
12776
|
container.appendChild( calendarButton.root );
|
|
12777
|
+
|
|
12778
|
+
if( dateAsRange )
|
|
12779
|
+
{
|
|
12780
|
+
const arrowRightIcon = LX.makeIcon( "ArrowRight" );
|
|
12781
|
+
LX.makeContainer( ["32px", "auto"], "content-center", arrowRightIcon.innerHTML, container );
|
|
12782
|
+
|
|
12783
|
+
const d1 = dts[ 1 ];
|
|
12784
|
+
const calendarIcon = LX.makeIcon( "Calendar" );
|
|
12785
|
+
const calendarButton = new LX.Button( null, d1, () => {
|
|
12786
|
+
this._popover = new LX.Popover( calendarButton.root, [ this.calendar ] );
|
|
12787
|
+
if( dateAsRange )
|
|
12788
|
+
{
|
|
12789
|
+
Object.assign( this._popover.root.style, { display: "flex", width: "auto" } );
|
|
12790
|
+
}
|
|
12791
|
+
}, { buttonClass: `flex flex-row px-3 ${ emptyDate ? "" : "fg-tertiary" } justify-between` } );
|
|
12792
|
+
calendarButton.root.querySelector( "button" ).appendChild( calendarIcon );
|
|
12793
|
+
calendarButton.root.style.width = "100%";
|
|
12794
|
+
container.appendChild( calendarButton.root );
|
|
12795
|
+
}
|
|
12473
12796
|
};
|
|
12474
12797
|
|
|
12475
|
-
|
|
12798
|
+
if( dateValue )
|
|
12799
|
+
{
|
|
12800
|
+
refresh( this.calendar.getFullDate() );
|
|
12801
|
+
}
|
|
12802
|
+
else
|
|
12803
|
+
{
|
|
12804
|
+
refresh();
|
|
12805
|
+
}
|
|
12476
12806
|
|
|
12477
12807
|
LX.doAsync( this.onResize.bind( this ) );
|
|
12478
12808
|
}
|
|
@@ -13138,6 +13468,7 @@ class Panel {
|
|
|
13138
13468
|
* img: Path to image to show as button value
|
|
13139
13469
|
* title: Text to show in native Element title
|
|
13140
13470
|
* buttonClass: Class to add to the native button element
|
|
13471
|
+
* mustConfirm: User must confirm trigger in a popover
|
|
13141
13472
|
*/
|
|
13142
13473
|
|
|
13143
13474
|
addButton( name, value, callback, options = {} ) {
|
|
@@ -13683,7 +14014,7 @@ class Panel {
|
|
|
13683
14014
|
/**
|
|
13684
14015
|
* @method addDate
|
|
13685
14016
|
* @param {String} name Widget name
|
|
13686
|
-
* @param {String}
|
|
14017
|
+
* @param {String} dateValue
|
|
13687
14018
|
* @param {Function} callback
|
|
13688
14019
|
* @param {Object} options:
|
|
13689
14020
|
* hideName: Don't use name as label [false]
|
|
@@ -13692,8 +14023,8 @@ class Panel {
|
|
|
13692
14023
|
* fromToday: Allow dates only from current day
|
|
13693
14024
|
*/
|
|
13694
14025
|
|
|
13695
|
-
addDate( name,
|
|
13696
|
-
const widget = new LX.DatePicker( name,
|
|
14026
|
+
addDate( name, dateValue, callback, options = { } ) {
|
|
14027
|
+
const widget = new LX.DatePicker( name, dateValue, callback, options );
|
|
13697
14028
|
return this._attachWidget( widget );
|
|
13698
14029
|
}
|
|
13699
14030
|
|
|
@@ -15828,4 +16159,303 @@ class AssetView {
|
|
|
15828
16159
|
|
|
15829
16160
|
LX.AssetView = AssetView;
|
|
15830
16161
|
|
|
16162
|
+
// tour.js @jxarco
|
|
16163
|
+
|
|
16164
|
+
class Tour {
|
|
16165
|
+
|
|
16166
|
+
static ACTIVE_TOURS = [];
|
|
16167
|
+
|
|
16168
|
+
/**
|
|
16169
|
+
* @constructor Tour
|
|
16170
|
+
* @param {Array} steps
|
|
16171
|
+
* @param {Object} options
|
|
16172
|
+
* useModal: Use a modal to highlight the tour step [true]
|
|
16173
|
+
* offset: Horizontal and vertical margin offset [0]
|
|
16174
|
+
* horizontalOffset: Horizontal offset [0]
|
|
16175
|
+
* verticalOffset: Vertical offset [0]
|
|
16176
|
+
* radius: Radius for the tour step highlight [8]
|
|
16177
|
+
*/
|
|
16178
|
+
|
|
16179
|
+
constructor( steps, options = {} ) {
|
|
16180
|
+
|
|
16181
|
+
this.steps = steps || [];
|
|
16182
|
+
this.currentStep = 0;
|
|
16183
|
+
|
|
16184
|
+
this.useModal = options.useModal ?? true;
|
|
16185
|
+
this.offset = options.offset ?? 8;
|
|
16186
|
+
this.horizontalOffset = options.horizontalOffset;
|
|
16187
|
+
this.verticalOffset = options.verticalOffset;
|
|
16188
|
+
this.radius = options.radius ?? 12;
|
|
16189
|
+
|
|
16190
|
+
this.tourContainer = document.querySelector( ".tour-container" );
|
|
16191
|
+
if( !this.tourContainer )
|
|
16192
|
+
{
|
|
16193
|
+
this.tourContainer = LX.makeContainer( ["100%", "100%"], "tour-container" );
|
|
16194
|
+
this.tourContainer.style.display = "none";
|
|
16195
|
+
document.body.appendChild( this.tourContainer );
|
|
16196
|
+
|
|
16197
|
+
window.addEventListener( "resize", () => {
|
|
16198
|
+
|
|
16199
|
+
for( const tour of Tour.ACTIVE_TOURS )
|
|
16200
|
+
{
|
|
16201
|
+
tour._showStep( 0 );
|
|
16202
|
+
}
|
|
16203
|
+
} );
|
|
16204
|
+
}
|
|
16205
|
+
}
|
|
16206
|
+
|
|
16207
|
+
/**
|
|
16208
|
+
* @method begin
|
|
16209
|
+
*/
|
|
16210
|
+
|
|
16211
|
+
begin() {
|
|
16212
|
+
|
|
16213
|
+
this.currentStep = 0;
|
|
16214
|
+
|
|
16215
|
+
this.tourContainer.style.display = "block";
|
|
16216
|
+
|
|
16217
|
+
Tour.ACTIVE_TOURS.push( this );
|
|
16218
|
+
|
|
16219
|
+
this._showStep( 0 );
|
|
16220
|
+
}
|
|
16221
|
+
|
|
16222
|
+
/**
|
|
16223
|
+
* @method stop
|
|
16224
|
+
*/
|
|
16225
|
+
|
|
16226
|
+
stop() {
|
|
16227
|
+
|
|
16228
|
+
if( this.useModal )
|
|
16229
|
+
{
|
|
16230
|
+
this.tourMask.remove();
|
|
16231
|
+
this.tourMask = undefined;
|
|
16232
|
+
}
|
|
16233
|
+
|
|
16234
|
+
this._popover?.destroy();
|
|
16235
|
+
|
|
16236
|
+
const index = Tour.ACTIVE_TOURS.indexOf( this );
|
|
16237
|
+
if( index !== -1 )
|
|
16238
|
+
{
|
|
16239
|
+
Tour.ACTIVE_TOURS.splice( index, 1 );
|
|
16240
|
+
}
|
|
16241
|
+
|
|
16242
|
+
this.tourContainer.innerHTML = "";
|
|
16243
|
+
this.tourContainer.style.display = "none";
|
|
16244
|
+
}
|
|
16245
|
+
|
|
16246
|
+
// Show the current step of the tour
|
|
16247
|
+
_showStep( stepOffset = 1 ) {
|
|
16248
|
+
|
|
16249
|
+
this.currentStep += stepOffset;
|
|
16250
|
+
|
|
16251
|
+
const step = this.steps[ this.currentStep ];
|
|
16252
|
+
if ( !step ) {
|
|
16253
|
+
this.stop();
|
|
16254
|
+
return;
|
|
16255
|
+
}
|
|
16256
|
+
|
|
16257
|
+
const prevStep = this.steps[ this.currentStep - 1 ];
|
|
16258
|
+
const nextStep = this.steps[ this.currentStep + 1 ];
|
|
16259
|
+
|
|
16260
|
+
if( this.useModal )
|
|
16261
|
+
{
|
|
16262
|
+
this._generateMask( step.reference );
|
|
16263
|
+
}
|
|
16264
|
+
|
|
16265
|
+
this._createHighlight( step, prevStep, nextStep );
|
|
16266
|
+
}
|
|
16267
|
+
|
|
16268
|
+
// Generate mask for the specific step reference
|
|
16269
|
+
// using a fullscreen SVG with "rect" elements
|
|
16270
|
+
_generateMask( reference ) {
|
|
16271
|
+
|
|
16272
|
+
this.tourContainer.innerHTML = ""; // Clear previous content
|
|
16273
|
+
|
|
16274
|
+
this.tourMask = LX.makeContainer( ["100%", "100%"], "tour-mask" );
|
|
16275
|
+
this.tourContainer.appendChild( this.tourMask );
|
|
16276
|
+
|
|
16277
|
+
const svg = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
|
|
16278
|
+
svg.style.width = "100%";
|
|
16279
|
+
svg.style.height = "100%";
|
|
16280
|
+
this.tourMask.appendChild( svg );
|
|
16281
|
+
|
|
16282
|
+
const clipPath = document.createElementNS( "http://www.w3.org/2000/svg", "clipPath" );
|
|
16283
|
+
clipPath.setAttribute( "id", "svgTourClipPath" );
|
|
16284
|
+
svg.appendChild( clipPath );
|
|
16285
|
+
|
|
16286
|
+
function ceilAndShiftRect( p, s ) {
|
|
16287
|
+
const cp = Math.ceil( p );
|
|
16288
|
+
const delta = cp - p;
|
|
16289
|
+
const ds = s - delta;
|
|
16290
|
+
return [ cp, ds ];
|
|
16291
|
+
}
|
|
16292
|
+
|
|
16293
|
+
const refBounding = reference.getBoundingClientRect();
|
|
16294
|
+
const [ boundingX, boundingWidth ] = ceilAndShiftRect( refBounding.x, refBounding.width );
|
|
16295
|
+
const [ boundingY, boundingHeight ] = ceilAndShiftRect( refBounding.y, refBounding.height );
|
|
16296
|
+
|
|
16297
|
+
const vOffset = this.verticalOffset ?? this.offset;
|
|
16298
|
+
const hOffset = this.horizontalOffset ?? this.offset;
|
|
16299
|
+
|
|
16300
|
+
// Left
|
|
16301
|
+
{
|
|
16302
|
+
const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16303
|
+
rect.setAttribute( "x", 0 );
|
|
16304
|
+
rect.setAttribute( "y", 0 );
|
|
16305
|
+
rect.setAttribute( "width", Math.max( 0, boundingX - hOffset ) );
|
|
16306
|
+
rect.setAttribute( "height", window.innerHeight );
|
|
16307
|
+
rect.setAttribute( "stroke", "none" );
|
|
16308
|
+
clipPath.appendChild( rect );
|
|
16309
|
+
}
|
|
16310
|
+
|
|
16311
|
+
// Top
|
|
16312
|
+
{
|
|
16313
|
+
const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16314
|
+
rect.setAttribute( "x", boundingX - hOffset );
|
|
16315
|
+
rect.setAttribute( "y", 0 );
|
|
16316
|
+
rect.setAttribute( "width", Math.max( 0, boundingWidth + hOffset * 2 ) );
|
|
16317
|
+
rect.setAttribute( "height", Math.max( 0, boundingY - vOffset ) );
|
|
16318
|
+
rect.setAttribute( "stroke", "none" );
|
|
16319
|
+
clipPath.appendChild( rect );
|
|
16320
|
+
}
|
|
16321
|
+
|
|
16322
|
+
// Bottom
|
|
16323
|
+
{
|
|
16324
|
+
const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16325
|
+
rect.setAttribute( "x", boundingX - hOffset );
|
|
16326
|
+
rect.setAttribute( "y", boundingY + boundingHeight + vOffset );
|
|
16327
|
+
rect.setAttribute( "width", Math.max( 0, boundingWidth + hOffset * 2 ) );
|
|
16328
|
+
rect.setAttribute( "height", Math.max( 0, window.innerHeight - boundingY - boundingHeight - vOffset ) );
|
|
16329
|
+
rect.setAttribute( "stroke", "none" );
|
|
16330
|
+
clipPath.appendChild( rect );
|
|
16331
|
+
}
|
|
16332
|
+
|
|
16333
|
+
// Right
|
|
16334
|
+
{
|
|
16335
|
+
const rect = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16336
|
+
rect.setAttribute( "x", boundingX + boundingWidth + hOffset );
|
|
16337
|
+
rect.setAttribute( "y", 0 );
|
|
16338
|
+
rect.setAttribute( "width", Math.max( 0, window.innerWidth - boundingX - boundingWidth ) );
|
|
16339
|
+
rect.setAttribute( "height", Math.max( 0, window.innerHeight ) );
|
|
16340
|
+
rect.setAttribute( "stroke", "none" );
|
|
16341
|
+
clipPath.appendChild( rect );
|
|
16342
|
+
}
|
|
16343
|
+
|
|
16344
|
+
// Reference Highlight
|
|
16345
|
+
const refContainer = LX.makeContainer( ["0", "0"], "tour-ref-mask" );
|
|
16346
|
+
refContainer.style.left = `${ boundingX - hOffset - 1 }px`;
|
|
16347
|
+
refContainer.style.top = `${ boundingY - vOffset - 1 }px`;
|
|
16348
|
+
refContainer.style.width = `${ boundingWidth + hOffset * 2 + 2 }px`;
|
|
16349
|
+
refContainer.style.height = `${ boundingHeight + vOffset * 2 + 2}px`;
|
|
16350
|
+
this.tourContainer.appendChild( refContainer );
|
|
16351
|
+
|
|
16352
|
+
const referenceMask = document.createElementNS( "http://www.w3.org/2000/svg", "mask" );
|
|
16353
|
+
referenceMask.setAttribute( "id", "svgTourReferenceMask" );
|
|
16354
|
+
svg.appendChild( referenceMask );
|
|
16355
|
+
|
|
16356
|
+
// Reference Mask
|
|
16357
|
+
{
|
|
16358
|
+
const rectWhite = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16359
|
+
rectWhite.setAttribute( "width", boundingWidth + hOffset * 2 + 2 );
|
|
16360
|
+
rectWhite.setAttribute( "height", boundingHeight + vOffset * 2 + 2);
|
|
16361
|
+
rectWhite.setAttribute( "stroke", "none" );
|
|
16362
|
+
rectWhite.setAttribute( "fill", "white" );
|
|
16363
|
+
referenceMask.appendChild( rectWhite );
|
|
16364
|
+
|
|
16365
|
+
const rectBlack = document.createElementNS( "http://www.w3.org/2000/svg", "rect" );
|
|
16366
|
+
rectBlack.setAttribute( "rx", this.radius );
|
|
16367
|
+
rectBlack.setAttribute( "width", boundingWidth + hOffset * 2 + 2);
|
|
16368
|
+
rectBlack.setAttribute( "height", boundingHeight + vOffset * 2 + 2);
|
|
16369
|
+
rectBlack.setAttribute( "stroke", "none" );
|
|
16370
|
+
rectBlack.setAttribute( "fill", "black" );
|
|
16371
|
+
referenceMask.appendChild( rectBlack );
|
|
16372
|
+
}
|
|
16373
|
+
}
|
|
16374
|
+
|
|
16375
|
+
// Create the container with the user hints
|
|
16376
|
+
_createHighlight( step, previousStep, nextStep ) {
|
|
16377
|
+
|
|
16378
|
+
const popoverContainer = LX.makeContainer( ["auto", "auto"], "tour-step-container" );
|
|
16379
|
+
|
|
16380
|
+
{
|
|
16381
|
+
const header = LX.makeContainer( ["100%", "auto"], "flex flex-row", "", popoverContainer );
|
|
16382
|
+
LX.makeContainer( ["70%", "auto"], "p-2 font-medium", step.title, header );
|
|
16383
|
+
const closer = LX.makeContainer( ["30%", "auto"], "flex flex-row p-2 justify-end", "", header );
|
|
16384
|
+
const closeIcon = LX.makeIcon( "X" );
|
|
16385
|
+
closer.appendChild( closeIcon );
|
|
16386
|
+
|
|
16387
|
+
closeIcon.listen( "click", () => {
|
|
16388
|
+
this.stop();
|
|
16389
|
+
} );
|
|
16390
|
+
}
|
|
16391
|
+
|
|
16392
|
+
LX.makeContainer( ["100%", "auto"], "p-2 text-md", step.content, popoverContainer, { maxWidth: "400px" } );
|
|
16393
|
+
const footer = LX.makeContainer( ["100%", "auto"], "flex flex-row text-md", "", popoverContainer );
|
|
16394
|
+
|
|
16395
|
+
{
|
|
16396
|
+
const footerSteps = LX.makeContainer( ["50%", "auto"], "p-2 gap-1 self-center flex flex-row text-md", "", footer );
|
|
16397
|
+
for( let i = 0; i < this.steps.length; i++ )
|
|
16398
|
+
{
|
|
16399
|
+
const stepIndicator = document.createElement( "span" );
|
|
16400
|
+
stepIndicator.className = "tour-step-indicator";
|
|
16401
|
+
if( i === this.currentStep )
|
|
16402
|
+
{
|
|
16403
|
+
stepIndicator.classList.add( "active" );
|
|
16404
|
+
}
|
|
16405
|
+
footerSteps.appendChild( stepIndicator );
|
|
16406
|
+
}
|
|
16407
|
+
}
|
|
16408
|
+
|
|
16409
|
+
const footerButtons = LX.makeContainer( ["50%", "auto"], "text-md", "", footer );
|
|
16410
|
+
const footerPanel = new LX.Panel();
|
|
16411
|
+
|
|
16412
|
+
let numButtons = 1;
|
|
16413
|
+
|
|
16414
|
+
if( previousStep )
|
|
16415
|
+
{
|
|
16416
|
+
numButtons++;
|
|
16417
|
+
}
|
|
16418
|
+
|
|
16419
|
+
if( numButtons > 1 )
|
|
16420
|
+
{
|
|
16421
|
+
footerPanel.sameLine( 2, "justify-end" );
|
|
16422
|
+
}
|
|
16423
|
+
|
|
16424
|
+
if( previousStep )
|
|
16425
|
+
{
|
|
16426
|
+
footerPanel.addButton( null, "Previous", () => {
|
|
16427
|
+
this._showStep( -1 );
|
|
16428
|
+
}, { buttonClass: "contrast" } );
|
|
16429
|
+
}
|
|
16430
|
+
|
|
16431
|
+
if( nextStep )
|
|
16432
|
+
{
|
|
16433
|
+
footerPanel.addButton( null, "Next", () => {
|
|
16434
|
+
this._showStep( 1 );
|
|
16435
|
+
}, { buttonClass: "accent" } );
|
|
16436
|
+
}
|
|
16437
|
+
else
|
|
16438
|
+
{
|
|
16439
|
+
footerPanel.addButton( null, "Finish", () => {
|
|
16440
|
+
this.stop();
|
|
16441
|
+
} );
|
|
16442
|
+
}
|
|
16443
|
+
|
|
16444
|
+
footerButtons.appendChild( footerPanel.root );
|
|
16445
|
+
|
|
16446
|
+
const sideOffset = ( step.side === "left" || step.side === "right" ? this.horizontalOffset : this.verticalOffset ) ?? this.offset;
|
|
16447
|
+
const alignOffset = ( step.align === "start" || step.align === "end" ? sideOffset : 0 );
|
|
16448
|
+
|
|
16449
|
+
this._popover?.destroy();
|
|
16450
|
+
this._popover = new LX.Popover( null, [ popoverContainer ], {
|
|
16451
|
+
reference: step.reference,
|
|
16452
|
+
side: step.side,
|
|
16453
|
+
align: step.align,
|
|
16454
|
+
sideOffset,
|
|
16455
|
+
alignOffset: step.align === "start" ? -alignOffset : alignOffset,
|
|
16456
|
+
} );
|
|
16457
|
+
}
|
|
16458
|
+
}
|
|
16459
|
+
LX.Tour = Tour;
|
|
16460
|
+
|
|
15831
16461
|
})( typeof(window) != 'undefined' ? window : (typeof(self) != 'undefined' ? self : global ) );
|