tiny-essentials 1.12.0 → 1.12.2
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/dist/legacy/firebase/index.mjs +5 -5
- package/dist/v1/TinyBasicsEs.js +1 -1257
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyDragger.js +148 -43
- package/dist/v1/TinyDragger.min.js +1 -1
- package/dist/v1/TinyEssentials.js +484 -189
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyUploadClicker.js +478 -190
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/basics/index.cjs +0 -23
- package/dist/v1/basics/index.d.mts +1 -23
- package/dist/v1/basics/index.mjs +1 -2
- package/dist/v1/fileManager/asyncFuncs.cjs +272 -0
- package/dist/v1/fileManager/asyncFuncs.d.mts +93 -0
- package/dist/v1/fileManager/asyncFuncs.mjs +236 -0
- package/dist/v1/fileManager/index.cjs +35 -0
- package/dist/v1/fileManager/index.d.mts +30 -0
- package/dist/v1/fileManager/index.mjs +3 -0
- package/dist/v1/{basics/fileManager.cjs → fileManager/normalFuncs.cjs} +10 -105
- package/dist/v1/{basics/fileManager.d.mts → fileManager/normalFuncs.d.mts} +3 -56
- package/dist/v1/{basics/fileManager.mjs → fileManager/normalFuncs.mjs} +48 -131
- package/dist/v1/index.cjs +30 -23
- package/dist/v1/index.d.mts +29 -23
- package/dist/v1/index.mjs +3 -2
- package/dist/v1/libs/TinyDragger.cjs +148 -43
- package/dist/v1/libs/TinyDragger.d.mts +18 -2
- package/dist/v1/libs/TinyDragger.mjs +132 -38
- package/dist/v1/libs/TinyUploadClicker.cjs +1 -0
- package/docs/v1/README.md +3 -1
- package/docs/v1/{basics/fileManager.md → fileManager/main.md} +12 -0
- package/docs/v1/libs/TinyDragger.md +15 -0
- package/package.json +5 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/******/ (() => { // webpackBootstrap
|
|
2
2
|
/******/ var __webpack_modules__ = ({
|
|
3
3
|
|
|
4
|
-
/***/
|
|
4
|
+
/***/ 133:
|
|
5
5
|
/***/ (() => {
|
|
6
6
|
|
|
7
7
|
/* (ignored) */
|
|
@@ -1924,6 +1924,13 @@ var hexSliceLookupTable = (function () {
|
|
|
1924
1924
|
})()
|
|
1925
1925
|
|
|
1926
1926
|
|
|
1927
|
+
/***/ }),
|
|
1928
|
+
|
|
1929
|
+
/***/ 370:
|
|
1930
|
+
/***/ (() => {
|
|
1931
|
+
|
|
1932
|
+
/* (ignored) */
|
|
1933
|
+
|
|
1927
1934
|
/***/ }),
|
|
1928
1935
|
|
|
1929
1936
|
/***/ 526:
|
|
@@ -3683,10 +3690,10 @@ const getHtmlElPadding = (el) => {
|
|
|
3683
3690
|
};
|
|
3684
3691
|
|
|
3685
3692
|
// EXTERNAL MODULE: fs (ignored)
|
|
3686
|
-
var fs_ignored_ = __webpack_require__(
|
|
3693
|
+
var fs_ignored_ = __webpack_require__(133);
|
|
3687
3694
|
// EXTERNAL MODULE: ./node_modules/path-browserify/index.js
|
|
3688
3695
|
var path_browserify = __webpack_require__(975);
|
|
3689
|
-
;// ./src/v1/
|
|
3696
|
+
;// ./src/v1/fileManager/normalFuncs.mjs
|
|
3690
3697
|
|
|
3691
3698
|
|
|
3692
3699
|
|
|
@@ -3702,8 +3709,8 @@ var path_browserify = __webpack_require__(975);
|
|
|
3702
3709
|
* @returns {any}
|
|
3703
3710
|
*/
|
|
3704
3711
|
function readJsonFile(filePath) {
|
|
3705
|
-
if (!
|
|
3706
|
-
const content =
|
|
3712
|
+
if (!existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
|
|
3713
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
3707
3714
|
return JSON.parse(content);
|
|
3708
3715
|
}
|
|
3709
3716
|
|
|
@@ -3716,32 +3723,7 @@ function readJsonFile(filePath) {
|
|
|
3716
3723
|
*/
|
|
3717
3724
|
function writeJsonFile(filePath, data, spaces = 2) {
|
|
3718
3725
|
const json = JSON.stringify(data, null, spaces);
|
|
3719
|
-
|
|
3720
|
-
}
|
|
3721
|
-
|
|
3722
|
-
/**
|
|
3723
|
-
* Reads and parses a JSON file.
|
|
3724
|
-
* Throws an error if the file content is not valid JSON.
|
|
3725
|
-
* @param {string} filePath
|
|
3726
|
-
* @returns {Promise<any>}
|
|
3727
|
-
*/
|
|
3728
|
-
async function readJsonFileAsync(filePath) {
|
|
3729
|
-
if (!fs.existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
|
|
3730
|
-
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
3731
|
-
return JSON.parse(content);
|
|
3732
|
-
}
|
|
3733
|
-
|
|
3734
|
-
/**
|
|
3735
|
-
* Saves an object as JSON to a file.
|
|
3736
|
-
* Automatically creates the directory if it does not exist.
|
|
3737
|
-
* @param {string} filePath
|
|
3738
|
-
* @param {any} data
|
|
3739
|
-
* @param {number} [spaces=2]
|
|
3740
|
-
* @returns {Promise<void>}
|
|
3741
|
-
*/
|
|
3742
|
-
function writeJsonFileAsync(filePath, data, spaces = 2) {
|
|
3743
|
-
const json = JSON.stringify(data, null, spaces);
|
|
3744
|
-
return fs.promises.writeFile(filePath, json, 'utf-8');
|
|
3726
|
+
writeFileSync(filePath, json, 'utf-8');
|
|
3745
3727
|
}
|
|
3746
3728
|
|
|
3747
3729
|
/*========================*
|
|
@@ -3752,9 +3734,9 @@ function writeJsonFileAsync(filePath, data, spaces = 2) {
|
|
|
3752
3734
|
* Ensures that the directory exists, creating it recursively if needed.
|
|
3753
3735
|
* @param {string} dirPath
|
|
3754
3736
|
*/
|
|
3755
|
-
function
|
|
3756
|
-
if (!
|
|
3757
|
-
|
|
3737
|
+
function normalFuncs_ensureDirectory(dirPath) {
|
|
3738
|
+
if (!existsSync(dirPath)) {
|
|
3739
|
+
mkdirSync(dirPath, { recursive: true });
|
|
3758
3740
|
}
|
|
3759
3741
|
}
|
|
3760
3742
|
|
|
@@ -3763,15 +3745,15 @@ function ensureDirectory(dirPath) {
|
|
|
3763
3745
|
* @param {string} dirPath
|
|
3764
3746
|
*/
|
|
3765
3747
|
function clearDirectory(dirPath) {
|
|
3766
|
-
if (!
|
|
3767
|
-
const files =
|
|
3748
|
+
if (!existsSync(dirPath)) return;
|
|
3749
|
+
const files = readdirSync(dirPath);
|
|
3768
3750
|
for (const file of files) {
|
|
3769
|
-
const fullPath =
|
|
3770
|
-
const
|
|
3771
|
-
if (
|
|
3772
|
-
|
|
3751
|
+
const fullPath = join(dirPath, file);
|
|
3752
|
+
const statData = lstatSync(fullPath);
|
|
3753
|
+
if (statData.isDirectory()) {
|
|
3754
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
3773
3755
|
} else {
|
|
3774
|
-
|
|
3756
|
+
unlinkSync(fullPath);
|
|
3775
3757
|
}
|
|
3776
3758
|
}
|
|
3777
3759
|
}
|
|
@@ -3785,8 +3767,8 @@ function clearDirectory(dirPath) {
|
|
|
3785
3767
|
* @param {string} filePath
|
|
3786
3768
|
* @returns {boolean}
|
|
3787
3769
|
*/
|
|
3788
|
-
function
|
|
3789
|
-
return
|
|
3770
|
+
function normalFuncs_fileExists(filePath) {
|
|
3771
|
+
return existsSync(filePath) && lstatSync(filePath).isFile();
|
|
3790
3772
|
}
|
|
3791
3773
|
|
|
3792
3774
|
/**
|
|
@@ -3794,8 +3776,8 @@ function fileExists(filePath) {
|
|
|
3794
3776
|
* @param {string} dirPath
|
|
3795
3777
|
* @returns {boolean}
|
|
3796
3778
|
*/
|
|
3797
|
-
function
|
|
3798
|
-
return
|
|
3779
|
+
function normalFuncs_dirExists(dirPath) {
|
|
3780
|
+
return existsSync(dirPath) && lstatSync(dirPath).isDirectory();
|
|
3799
3781
|
}
|
|
3800
3782
|
|
|
3801
3783
|
/**
|
|
@@ -3804,7 +3786,7 @@ function dirExists(dirPath) {
|
|
|
3804
3786
|
* @returns {boolean}
|
|
3805
3787
|
*/
|
|
3806
3788
|
function isDirEmpty(dirPath) {
|
|
3807
|
-
return
|
|
3789
|
+
return readdirSync(dirPath).length === 0;
|
|
3808
3790
|
}
|
|
3809
3791
|
|
|
3810
3792
|
/*========================*
|
|
@@ -3818,8 +3800,8 @@ function isDirEmpty(dirPath) {
|
|
|
3818
3800
|
* @param {number} [mode]
|
|
3819
3801
|
*/
|
|
3820
3802
|
function ensureCopyFile(src, dest, mode) {
|
|
3821
|
-
|
|
3822
|
-
|
|
3803
|
+
normalFuncs_ensureDirectory(dirname(dest));
|
|
3804
|
+
copyFileSync(src, dest, mode);
|
|
3823
3805
|
}
|
|
3824
3806
|
|
|
3825
3807
|
/**
|
|
@@ -3828,33 +3810,8 @@ function ensureCopyFile(src, dest, mode) {
|
|
|
3828
3810
|
* @returns {boolean}
|
|
3829
3811
|
*/
|
|
3830
3812
|
function tryDeleteFile(filePath) {
|
|
3831
|
-
if (
|
|
3832
|
-
|
|
3833
|
-
return true;
|
|
3834
|
-
}
|
|
3835
|
-
return false;
|
|
3836
|
-
}
|
|
3837
|
-
|
|
3838
|
-
/**
|
|
3839
|
-
* Copies a file to a destination.
|
|
3840
|
-
* @param {string} src
|
|
3841
|
-
* @param {string} dest
|
|
3842
|
-
* @param {number} [mode]
|
|
3843
|
-
* @returns {Promise<void>}
|
|
3844
|
-
*/
|
|
3845
|
-
function ensureCopyFileAsync(src, dest, mode) {
|
|
3846
|
-
ensureDirectory(path.dirname(dest));
|
|
3847
|
-
return fs.promises.copyFile(src, dest, mode);
|
|
3848
|
-
}
|
|
3849
|
-
|
|
3850
|
-
/**
|
|
3851
|
-
* Deletes a file (If the file exists).
|
|
3852
|
-
* @param {string} filePath
|
|
3853
|
-
* @returns {Promise<boolean>}
|
|
3854
|
-
*/
|
|
3855
|
-
async function tryDeleteFileAsync(filePath) {
|
|
3856
|
-
if (fileExists(filePath)) {
|
|
3857
|
-
await fs.promises.unlink(filePath);
|
|
3813
|
+
if (normalFuncs_fileExists(filePath)) {
|
|
3814
|
+
unlinkSync(filePath);
|
|
3858
3815
|
return true;
|
|
3859
3816
|
}
|
|
3860
3817
|
return false;
|
|
@@ -3868,25 +3825,12 @@ async function tryDeleteFileAsync(filePath) {
|
|
|
3868
3825
|
* Writes text to a file (Ensures that the directory exists, creating it recursively if needed).
|
|
3869
3826
|
* @param {string} filePath
|
|
3870
3827
|
* @param {string} content
|
|
3871
|
-
* @param {fs.WriteFileOptions} [ops='utf-8']
|
|
3828
|
+
* @param {import('fs').WriteFileOptions} [ops='utf-8']
|
|
3872
3829
|
*/
|
|
3873
3830
|
function writeTextFile(filePath, content, ops = 'utf-8') {
|
|
3874
|
-
const dir =
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
}
|
|
3878
|
-
|
|
3879
|
-
/**
|
|
3880
|
-
* Writes text to a file (Ensures that the directory exists, creating it recursively if needed).
|
|
3881
|
-
* @param {string} filePath
|
|
3882
|
-
* @param {string} content
|
|
3883
|
-
* @param {fs.WriteFileOptions} [ops='utf-8']
|
|
3884
|
-
* @returns {Promise<void>}
|
|
3885
|
-
*/
|
|
3886
|
-
function writeTextFileAsync(filePath, content, ops = 'utf-8') {
|
|
3887
|
-
const dir = path.dirname(filePath);
|
|
3888
|
-
ensureDirectory(dir);
|
|
3889
|
-
return fs.promises.writeFile(filePath, content, ops);
|
|
3831
|
+
const dir = dirname(filePath);
|
|
3832
|
+
normalFuncs_ensureDirectory(dir);
|
|
3833
|
+
writeFileSync(filePath, content, ops);
|
|
3890
3834
|
}
|
|
3891
3835
|
|
|
3892
3836
|
/*========================*
|
|
@@ -3902,13 +3846,13 @@ function writeTextFileAsync(filePath, content, ops = 'utf-8') {
|
|
|
3902
3846
|
function listFiles(dirPath, recursive = false) {
|
|
3903
3847
|
/** @type {{ files: string[]; dirs: string[] }} */
|
|
3904
3848
|
const results = { files: [], dirs: [] };
|
|
3905
|
-
if (!
|
|
3849
|
+
if (!normalFuncs_dirExists(dirPath)) return results;
|
|
3906
3850
|
|
|
3907
|
-
const entries =
|
|
3851
|
+
const entries = readdirSync(dirPath);
|
|
3908
3852
|
for (const entry of entries) {
|
|
3909
|
-
const fullPath =
|
|
3910
|
-
const
|
|
3911
|
-
if (
|
|
3853
|
+
const fullPath = join(dirPath, entry);
|
|
3854
|
+
const statData = lstatSync(fullPath);
|
|
3855
|
+
if (statData.isDirectory()) {
|
|
3912
3856
|
results.dirs.push(fullPath);
|
|
3913
3857
|
if (recursive) {
|
|
3914
3858
|
const results2 = listFiles(fullPath, true);
|
|
@@ -3931,13 +3875,13 @@ function listFiles(dirPath, recursive = false) {
|
|
|
3931
3875
|
function listDirs(dirPath, recursive = false) {
|
|
3932
3876
|
/** @type {string[]} */
|
|
3933
3877
|
const results = [];
|
|
3934
|
-
if (!
|
|
3878
|
+
if (!normalFuncs_dirExists(dirPath)) return results;
|
|
3935
3879
|
|
|
3936
|
-
const entries =
|
|
3880
|
+
const entries = readdirSync(dirPath);
|
|
3937
3881
|
for (const entry of entries) {
|
|
3938
|
-
const fullPath =
|
|
3939
|
-
const
|
|
3940
|
-
if (
|
|
3882
|
+
const fullPath = join(dirPath, entry);
|
|
3883
|
+
const statData = lstatSync(fullPath);
|
|
3884
|
+
if (statData.isDirectory()) {
|
|
3941
3885
|
results.push(fullPath);
|
|
3942
3886
|
if (recursive) {
|
|
3943
3887
|
results.push(...listDirs(fullPath, true));
|
|
@@ -3957,8 +3901,8 @@ function listDirs(dirPath, recursive = false) {
|
|
|
3957
3901
|
* @returns {number}
|
|
3958
3902
|
*/
|
|
3959
3903
|
function fileSize(filePath) {
|
|
3960
|
-
if (!
|
|
3961
|
-
const stats =
|
|
3904
|
+
if (!normalFuncs_fileExists(filePath)) return 0;
|
|
3905
|
+
const stats = statSync(filePath);
|
|
3962
3906
|
return stats.size;
|
|
3963
3907
|
}
|
|
3964
3908
|
|
|
@@ -3986,7 +3930,7 @@ function dirSize(dirPath) {
|
|
|
3986
3930
|
* @param {string} [ext='bak']
|
|
3987
3931
|
*/
|
|
3988
3932
|
function backupFile(filePath, ext = 'bak') {
|
|
3989
|
-
if (!
|
|
3933
|
+
if (!normalFuncs_fileExists(filePath)) return;
|
|
3990
3934
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
3991
3935
|
const backupPath = `${filePath}.${ext}.${timestamp}`;
|
|
3992
3936
|
ensureCopyFile(filePath, backupPath);
|
|
@@ -3998,18 +3942,17 @@ function backupFile(filePath, ext = 'bak') {
|
|
|
3998
3942
|
* @param {string} [ext='bak']
|
|
3999
3943
|
* @returns {string} Full path to the most recent backup
|
|
4000
3944
|
*/
|
|
4001
|
-
function
|
|
4002
|
-
const dir =
|
|
4003
|
-
const baseName =
|
|
4004
|
-
const backups =
|
|
4005
|
-
.readdirSync(dir)
|
|
3945
|
+
function normalFuncs_getLatestBackupPath(filePath, ext = 'bak') {
|
|
3946
|
+
const dir = dirname(filePath);
|
|
3947
|
+
const baseName = basename(filePath);
|
|
3948
|
+
const backups = readdirSync(dir)
|
|
4006
3949
|
.filter((name) => name.startsWith(`${baseName}.${ext}.`))
|
|
4007
3950
|
.sort()
|
|
4008
3951
|
.reverse();
|
|
4009
3952
|
|
|
4010
3953
|
if (backups.length === 0) throw new Error(`No backups found for ${filePath}`);
|
|
4011
3954
|
|
|
4012
|
-
return
|
|
3955
|
+
return join(dir, backups[0]);
|
|
4013
3956
|
}
|
|
4014
3957
|
|
|
4015
3958
|
/**
|
|
@@ -4018,34 +3961,10 @@ function getLatestBackupPath(filePath, ext = 'bak') {
|
|
|
4018
3961
|
* @param {string} [ext='bak']
|
|
4019
3962
|
*/
|
|
4020
3963
|
function restoreLatestBackup(filePath, ext = 'bak') {
|
|
4021
|
-
const latestBackup =
|
|
3964
|
+
const latestBackup = normalFuncs_getLatestBackupPath(filePath, ext);
|
|
4022
3965
|
ensureCopyFile(latestBackup, filePath);
|
|
4023
3966
|
}
|
|
4024
3967
|
|
|
4025
|
-
/**
|
|
4026
|
-
* Restores the most recent backup of a file.
|
|
4027
|
-
* @param {string} filePath
|
|
4028
|
-
* @param {string} [ext='bak']
|
|
4029
|
-
* @returns {Promise<void>}
|
|
4030
|
-
*/
|
|
4031
|
-
function restoreLatestBackupAsync(filePath, ext = 'bak') {
|
|
4032
|
-
const latestBackup = getLatestBackupPath(filePath, ext);
|
|
4033
|
-
return ensureCopyFileAsync(latestBackup, filePath);
|
|
4034
|
-
}
|
|
4035
|
-
|
|
4036
|
-
/**
|
|
4037
|
-
* Creates a backup copy of a file with .bak timestamp suffix.
|
|
4038
|
-
* @param {string} filePath
|
|
4039
|
-
* @param {string} [ext='bak']
|
|
4040
|
-
* @returns {Promise<void>}
|
|
4041
|
-
*/
|
|
4042
|
-
async function backupFileAsync(filePath, ext = 'bak') {
|
|
4043
|
-
if (!fileExists(filePath)) return;
|
|
4044
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
4045
|
-
const backupPath = `${filePath}.${ext}.${timestamp}`;
|
|
4046
|
-
return ensureCopyFileAsync(filePath, backupPath);
|
|
4047
|
-
}
|
|
4048
|
-
|
|
4049
3968
|
/*========================*
|
|
4050
3969
|
* Rename Utilities
|
|
4051
3970
|
*========================*/
|
|
@@ -4064,7 +3983,7 @@ function renameFileBatch(dirPath, renameFn, extensions = []) {
|
|
|
4064
3983
|
if (typeof dirPath !== 'string') throw new TypeError('dirPath must be a string');
|
|
4065
3984
|
if (typeof renameFn !== 'function') throw new TypeError('renameFn must be a function');
|
|
4066
3985
|
if (!Array.isArray(extensions)) throw new TypeError('extensions must be an array of strings');
|
|
4067
|
-
if (!
|
|
3986
|
+
if (!existsSync(dirPath) || !statSync(dirPath).isDirectory())
|
|
4068
3987
|
throw new Error(`Directory not found or invalid: ${dirPath}`);
|
|
4069
3988
|
for (const ext of extensions) {
|
|
4070
3989
|
if (typeof ext !== 'string' || !ext.startsWith('.'))
|
|
@@ -4075,16 +3994,16 @@ function renameFileBatch(dirPath, renameFn, extensions = []) {
|
|
|
4075
3994
|
let index = 0;
|
|
4076
3995
|
|
|
4077
3996
|
for (const file of files) {
|
|
4078
|
-
const ext =
|
|
3997
|
+
const ext = extname(file);
|
|
4079
3998
|
if (extensions.length && !extensions.includes(ext)) continue;
|
|
4080
3999
|
|
|
4081
|
-
const originalName =
|
|
4000
|
+
const originalName = basename(file);
|
|
4082
4001
|
const newName = renameFn(originalName, index++);
|
|
4083
|
-
const newPath =
|
|
4002
|
+
const newPath = join(dirPath, newName);
|
|
4084
4003
|
|
|
4085
4004
|
if (originalName === newName) continue;
|
|
4086
4005
|
|
|
4087
|
-
|
|
4006
|
+
renameSync(file, newPath);
|
|
4088
4007
|
}
|
|
4089
4008
|
}
|
|
4090
4009
|
|
|
@@ -4099,8 +4018,8 @@ function renameFileRegex(dirPath, pattern, replacement, extensions = []) {
|
|
|
4099
4018
|
renameFileBatch(
|
|
4100
4019
|
dirPath,
|
|
4101
4020
|
(filename) => {
|
|
4102
|
-
const ext =
|
|
4103
|
-
const name =
|
|
4021
|
+
const ext = extname(filename);
|
|
4022
|
+
const name = basename(filename, ext).replace(pattern, replacement);
|
|
4104
4023
|
return `${name}${ext}`;
|
|
4105
4024
|
},
|
|
4106
4025
|
extensions,
|
|
@@ -4117,8 +4036,8 @@ function renameFileAddPrefixSuffix(dirPath, { prefix = '', suffix = '' }, extens
|
|
|
4117
4036
|
renameFileBatch(
|
|
4118
4037
|
dirPath,
|
|
4119
4038
|
(filename) => {
|
|
4120
|
-
const ext =
|
|
4121
|
-
const name =
|
|
4039
|
+
const ext = extname(filename);
|
|
4040
|
+
const name = basename(filename, ext);
|
|
4122
4041
|
return `${prefix}${name}${suffix}${ext}`;
|
|
4123
4042
|
},
|
|
4124
4043
|
extensions,
|
|
@@ -4155,9 +4074,9 @@ function renameFileNormalizeCase(
|
|
|
4155
4074
|
else return text;
|
|
4156
4075
|
};
|
|
4157
4076
|
|
|
4158
|
-
const rawExt =
|
|
4077
|
+
const rawExt = extname(filename);
|
|
4159
4078
|
const ext = normalizeExt ? changeToMode(rawExt) : rawExt;
|
|
4160
|
-
const name = changeToMode(
|
|
4079
|
+
const name = changeToMode(basename(filename, rawExt));
|
|
4161
4080
|
return `${name}${ext}`;
|
|
4162
4081
|
},
|
|
4163
4082
|
extensions,
|
|
@@ -4180,6 +4099,266 @@ function renameFilePadNumbers(dirPath, totalDigits = 3, extensions = []) {
|
|
|
4180
4099
|
);
|
|
4181
4100
|
}
|
|
4182
4101
|
|
|
4102
|
+
// EXTERNAL MODULE: fs/promises (ignored)
|
|
4103
|
+
var promises_ignored_ = __webpack_require__(370);
|
|
4104
|
+
;// ./src/v1/fileManager/asyncFuncs.mjs
|
|
4105
|
+
|
|
4106
|
+
|
|
4107
|
+
|
|
4108
|
+
|
|
4109
|
+
|
|
4110
|
+
/*========================*
|
|
4111
|
+
* JSON Operations
|
|
4112
|
+
*========================*/
|
|
4113
|
+
|
|
4114
|
+
/**
|
|
4115
|
+
* Reads and parses a JSON file.
|
|
4116
|
+
* Throws an error if the file content is not valid JSON.
|
|
4117
|
+
* @param {string} filePath
|
|
4118
|
+
* @returns {Promise<any>}
|
|
4119
|
+
*/
|
|
4120
|
+
async function readJsonFileAsync(filePath) {
|
|
4121
|
+
if (!existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
|
|
4122
|
+
const content = await readFile(filePath, 'utf-8');
|
|
4123
|
+
return JSON.parse(content);
|
|
4124
|
+
}
|
|
4125
|
+
|
|
4126
|
+
/**
|
|
4127
|
+
* Saves an object as JSON to a file.
|
|
4128
|
+
* Automatically creates the directory if it does not exist.
|
|
4129
|
+
* @param {string} filePath
|
|
4130
|
+
* @param {any} data
|
|
4131
|
+
* @param {number} [spaces=2]
|
|
4132
|
+
* @returns {Promise<void>}
|
|
4133
|
+
*/
|
|
4134
|
+
function writeJsonFileAsync(filePath, data, spaces = 2) {
|
|
4135
|
+
const json = JSON.stringify(data, null, spaces);
|
|
4136
|
+
return writeFile(filePath, json, 'utf-8');
|
|
4137
|
+
}
|
|
4138
|
+
|
|
4139
|
+
/*========================*
|
|
4140
|
+
* Directory Management
|
|
4141
|
+
*========================*/
|
|
4142
|
+
|
|
4143
|
+
/**
|
|
4144
|
+
* Clears all contents inside a directory but keeps the directory.
|
|
4145
|
+
* @param {string} dirPath
|
|
4146
|
+
*/
|
|
4147
|
+
async function clearDirectoryAsync(dirPath) {
|
|
4148
|
+
if (!existsSync(dirPath)) return;
|
|
4149
|
+
const files = await readdir(dirPath);
|
|
4150
|
+
|
|
4151
|
+
/** @type {Record<string, import('fs').Stats>} */
|
|
4152
|
+
const dataList = {};
|
|
4153
|
+
const promises = [];
|
|
4154
|
+
|
|
4155
|
+
for (const file of files) {
|
|
4156
|
+
const fullPath = join(dirPath, file);
|
|
4157
|
+
const lsResult = lstat(fullPath);
|
|
4158
|
+
|
|
4159
|
+
lsResult.then((statData) => {
|
|
4160
|
+
dataList[fullPath] = statData;
|
|
4161
|
+
return statData;
|
|
4162
|
+
});
|
|
4163
|
+
promises.push(lsResult);
|
|
4164
|
+
}
|
|
4165
|
+
|
|
4166
|
+
await Promise.all(promises);
|
|
4167
|
+
const promises2 = [];
|
|
4168
|
+
for (const fullPath in dataList) {
|
|
4169
|
+
const statData = dataList[fullPath];
|
|
4170
|
+
if (statData.isDirectory()) {
|
|
4171
|
+
promises2.push(rm(fullPath, { recursive: true, force: true }));
|
|
4172
|
+
} else {
|
|
4173
|
+
promises2.push(unlink(fullPath));
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
|
|
4177
|
+
await Promise.all(promises2);
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
/*========================*
|
|
4181
|
+
* File Checks
|
|
4182
|
+
*========================*/
|
|
4183
|
+
|
|
4184
|
+
/**
|
|
4185
|
+
* Checks whether a directory is empty.
|
|
4186
|
+
* @param {string} dirPath
|
|
4187
|
+
* @returns {Promise<boolean>}
|
|
4188
|
+
*/
|
|
4189
|
+
async function isDirEmptyAsync(dirPath) {
|
|
4190
|
+
const data = await readdir(dirPath);
|
|
4191
|
+
return data.length === 0;
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4194
|
+
/*========================*
|
|
4195
|
+
* File Operations
|
|
4196
|
+
*========================*/
|
|
4197
|
+
|
|
4198
|
+
/**
|
|
4199
|
+
* Copies a file to a destination.
|
|
4200
|
+
* @param {string} src
|
|
4201
|
+
* @param {string} dest
|
|
4202
|
+
* @param {number} [mode]
|
|
4203
|
+
* @returns {Promise<void>}
|
|
4204
|
+
*/
|
|
4205
|
+
function ensureCopyFileAsync(src, dest, mode) {
|
|
4206
|
+
ensureDirectory(dirname(dest));
|
|
4207
|
+
return copyFile(src, dest, mode);
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4210
|
+
/**
|
|
4211
|
+
* Deletes a file (If the file exists).
|
|
4212
|
+
* @param {string} filePath
|
|
4213
|
+
* @returns {Promise<boolean>}
|
|
4214
|
+
*/
|
|
4215
|
+
async function tryDeleteFileAsync(filePath) {
|
|
4216
|
+
if (fileExists(filePath)) {
|
|
4217
|
+
await unlink(filePath);
|
|
4218
|
+
return true;
|
|
4219
|
+
}
|
|
4220
|
+
return false;
|
|
4221
|
+
}
|
|
4222
|
+
|
|
4223
|
+
/*========================*
|
|
4224
|
+
* Text Operations
|
|
4225
|
+
*========================*/
|
|
4226
|
+
|
|
4227
|
+
/**
|
|
4228
|
+
* Writes text to a file (Ensures that the directory exists, creating it recursively if needed).
|
|
4229
|
+
* @param {string} filePath
|
|
4230
|
+
* @param {string} content
|
|
4231
|
+
* @param {import('fs').WriteFileOptions} [ops='utf-8']
|
|
4232
|
+
* @returns {Promise<void>}
|
|
4233
|
+
*/
|
|
4234
|
+
function writeTextFileAsync(filePath, content, ops = 'utf-8') {
|
|
4235
|
+
const dir = dirname(filePath);
|
|
4236
|
+
ensureDirectory(dir);
|
|
4237
|
+
return writeFile(filePath, content, ops);
|
|
4238
|
+
}
|
|
4239
|
+
|
|
4240
|
+
/*========================*
|
|
4241
|
+
* Directory Listings
|
|
4242
|
+
*========================*/
|
|
4243
|
+
|
|
4244
|
+
/**
|
|
4245
|
+
* Lists all files and dirs in a directory (optionally recursive).
|
|
4246
|
+
* @param {string} dirPath
|
|
4247
|
+
* @param {boolean} [recursive=false]
|
|
4248
|
+
* @returns {Promise<{ files: string[]; dirs: string[] }>}
|
|
4249
|
+
*/
|
|
4250
|
+
async function listFilesAsync(dirPath, recursive = false) {
|
|
4251
|
+
/** @type {{ files: string[]; dirs: string[] }} */
|
|
4252
|
+
const results = { files: [], dirs: [] };
|
|
4253
|
+
if (!dirExists(dirPath)) return results;
|
|
4254
|
+
|
|
4255
|
+
const entries = await readdir(dirPath);
|
|
4256
|
+
for (const entry of entries) {
|
|
4257
|
+
const fullPath = join(dirPath, entry);
|
|
4258
|
+
const statData = await lstat(fullPath);
|
|
4259
|
+
if (statData.isDirectory()) {
|
|
4260
|
+
results.dirs.push(fullPath);
|
|
4261
|
+
if (recursive) {
|
|
4262
|
+
const results2 = await listFilesAsync(fullPath, true);
|
|
4263
|
+
results.files.push(...results2.files);
|
|
4264
|
+
results.dirs.push(...results2.dirs);
|
|
4265
|
+
}
|
|
4266
|
+
} else {
|
|
4267
|
+
results.files.push(fullPath);
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
return results;
|
|
4271
|
+
}
|
|
4272
|
+
|
|
4273
|
+
/**
|
|
4274
|
+
* Lists all directories in a directory (optionally recursive).
|
|
4275
|
+
* @param {string} dirPath
|
|
4276
|
+
* @param {boolean} [recursive=false]
|
|
4277
|
+
* @returns {Promise<string[]>}
|
|
4278
|
+
*/
|
|
4279
|
+
async function listDirsAsync(dirPath, recursive = false) {
|
|
4280
|
+
/** @type {string[]} */
|
|
4281
|
+
const results = [];
|
|
4282
|
+
if (!dirExists(dirPath)) return results;
|
|
4283
|
+
|
|
4284
|
+
const entries = await readdir(dirPath);
|
|
4285
|
+
for (const entry of entries) {
|
|
4286
|
+
const fullPath = join(dirPath, entry);
|
|
4287
|
+
const statData = await lstat(fullPath);
|
|
4288
|
+
if (statData.isDirectory()) {
|
|
4289
|
+
results.push(fullPath);
|
|
4290
|
+
if (recursive) {
|
|
4291
|
+
results.push(...(await listDirsAsync(fullPath, true)));
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
return results;
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
/*========================*
|
|
4299
|
+
* File Info
|
|
4300
|
+
*========================*/
|
|
4301
|
+
|
|
4302
|
+
/**
|
|
4303
|
+
* Returns the size of a file in bytes.
|
|
4304
|
+
* @param {string} filePath
|
|
4305
|
+
* @returns {Promise<number>}
|
|
4306
|
+
*/
|
|
4307
|
+
async function fileSizeAsync(filePath) {
|
|
4308
|
+
if (!fileExists(filePath)) return 0;
|
|
4309
|
+
const stats = await stat(filePath);
|
|
4310
|
+
return stats.size;
|
|
4311
|
+
}
|
|
4312
|
+
|
|
4313
|
+
/**
|
|
4314
|
+
* Returns the total size of a directory in bytes.
|
|
4315
|
+
* @param {string} dirPath
|
|
4316
|
+
* @returns {Promise<number>}
|
|
4317
|
+
*/
|
|
4318
|
+
async function dirSizeAsync(dirPath) {
|
|
4319
|
+
let total = 0;
|
|
4320
|
+
const { files } = await listFilesAsync(dirPath, true);
|
|
4321
|
+
const promises = [];
|
|
4322
|
+
for (const file of files) {
|
|
4323
|
+
const result = fileSizeAsync(file);
|
|
4324
|
+
result.then((item) => {
|
|
4325
|
+
total += item;
|
|
4326
|
+
return item;
|
|
4327
|
+
});
|
|
4328
|
+
promises.push(result);
|
|
4329
|
+
}
|
|
4330
|
+
await Promise.all(promises);
|
|
4331
|
+
return total;
|
|
4332
|
+
}
|
|
4333
|
+
|
|
4334
|
+
/*========================*
|
|
4335
|
+
* Backup Utilities
|
|
4336
|
+
*========================*/
|
|
4337
|
+
|
|
4338
|
+
/**
|
|
4339
|
+
* Restores the most recent backup of a file.
|
|
4340
|
+
* @param {string} filePath
|
|
4341
|
+
* @param {string} [ext='bak']
|
|
4342
|
+
* @returns {Promise<void>}
|
|
4343
|
+
*/
|
|
4344
|
+
function restoreLatestBackupAsync(filePath, ext = 'bak') {
|
|
4345
|
+
const latestBackup = getLatestBackupPath(filePath, ext);
|
|
4346
|
+
return ensureCopyFileAsync(latestBackup, filePath);
|
|
4347
|
+
}
|
|
4348
|
+
|
|
4349
|
+
/**
|
|
4350
|
+
* Creates a backup copy of a file with .bak timestamp suffix.
|
|
4351
|
+
* @param {string} filePath
|
|
4352
|
+
* @param {string} [ext='bak']
|
|
4353
|
+
* @returns {Promise<void>}
|
|
4354
|
+
*/
|
|
4355
|
+
async function backupFileAsync(filePath, ext = 'bak') {
|
|
4356
|
+
if (!fileExists(filePath)) return;
|
|
4357
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
4358
|
+
const backupPath = `${filePath}.${ext}.${timestamp}`;
|
|
4359
|
+
return ensureCopyFileAsync(filePath, backupPath);
|
|
4360
|
+
}
|
|
4361
|
+
|
|
4183
4362
|
;// ./src/v1/libs/TinyDragger.mjs
|
|
4184
4363
|
|
|
4185
4364
|
|
|
@@ -4204,6 +4383,7 @@ class TinyDragger {
|
|
|
4204
4383
|
#offsetY = 0;
|
|
4205
4384
|
#offsetX = 0;
|
|
4206
4385
|
|
|
4386
|
+
#multiCollision = false;
|
|
4207
4387
|
#lockInsideJail = false;
|
|
4208
4388
|
#revertOnDrop = false;
|
|
4209
4389
|
#dragging = false;
|
|
@@ -4248,6 +4428,7 @@ class TinyDragger {
|
|
|
4248
4428
|
* @param {string} [options.classDragCollision='dragging-collision'] - CSS class applied to collision element.
|
|
4249
4429
|
* @param {boolean} [options.lockInsideJail=false] - Restrict movement within the jail container.
|
|
4250
4430
|
* @param {boolean} [options.dropInJailOnly=false] - Restrict drop within the jail container.
|
|
4431
|
+
* @param {boolean} [options.multiCollision=false] - Enables returning multiple collided elements.
|
|
4251
4432
|
* @param {VibrationPatterns|false} [options.vibration=false] - Vibration feedback configuration.
|
|
4252
4433
|
* @param {boolean} [options.revertOnDrop=false] - Whether to return to original position on drop.
|
|
4253
4434
|
* @param {string} [options.classHidden='drag-hidden'] - CSS class to hide original element during dragging.
|
|
@@ -4294,6 +4475,7 @@ class TinyDragger {
|
|
|
4294
4475
|
validateBoolean(options.lockInsideJail, 'lockInsideJail');
|
|
4295
4476
|
validateBoolean(options.dropInJailOnly, 'dropInJailOnly');
|
|
4296
4477
|
validateBoolean(options.revertOnDrop, 'revertOnDrop');
|
|
4478
|
+
validateBoolean(options.multiCollision, 'multiCollision');
|
|
4297
4479
|
|
|
4298
4480
|
validateString(options.classDragging, 'classDragging');
|
|
4299
4481
|
validateString(options.classBodyDragging, 'classBodyDragging');
|
|
@@ -4327,6 +4509,7 @@ class TinyDragger {
|
|
|
4327
4509
|
if (typeof options.revertOnDrop === 'boolean') this.#revertOnDrop = options.revertOnDrop;
|
|
4328
4510
|
if (typeof options.lockInsideJail === 'boolean') this.#lockInsideJail = options.lockInsideJail;
|
|
4329
4511
|
if (typeof options.dropInJailOnly === 'boolean') this.#dropInJailOnly = options.dropInJailOnly;
|
|
4512
|
+
if (typeof options.multiCollision === 'boolean') this.#multiCollision = options.multiCollision;
|
|
4330
4513
|
|
|
4331
4514
|
/** @private */
|
|
4332
4515
|
this._onMouseDown = this.#startDrag.bind(this);
|
|
@@ -4518,22 +4701,67 @@ class TinyDragger {
|
|
|
4518
4701
|
this.#dispatchEvent('drag');
|
|
4519
4702
|
}
|
|
4520
4703
|
|
|
4704
|
+
/** @type {HTMLElement[]} */
|
|
4705
|
+
#collisionsMarked = [];
|
|
4706
|
+
|
|
4707
|
+
/**
|
|
4708
|
+
* Marks an element as currently collided by adding the collision CSS class.
|
|
4709
|
+
* The element is stored in an internal list for easy removal later.
|
|
4710
|
+
*
|
|
4711
|
+
* @param {HTMLElement|null} el - The element to mark as collided.
|
|
4712
|
+
*/
|
|
4713
|
+
#addCollision(el) {
|
|
4714
|
+
if (!el) return;
|
|
4715
|
+
el.classList.add(this.#classDragCollision);
|
|
4716
|
+
this.#collisionsMarked.push(el);
|
|
4717
|
+
}
|
|
4718
|
+
|
|
4719
|
+
/**
|
|
4720
|
+
* Removes the collision CSS class from all previously marked elements.
|
|
4721
|
+
* Also clears the last single collision element, if set.
|
|
4722
|
+
*
|
|
4723
|
+
*/
|
|
4724
|
+
#removeCollision() {
|
|
4725
|
+
while (this.#collisionsMarked.length > 0) {
|
|
4726
|
+
const el = this.#collisionsMarked.shift();
|
|
4727
|
+
if (el) el.classList.remove(this.#classDragCollision);
|
|
4728
|
+
}
|
|
4729
|
+
if (!this.#lastCollision) return;
|
|
4730
|
+
this.#lastCollision.classList.remove(this.#classDragCollision);
|
|
4731
|
+
}
|
|
4732
|
+
|
|
4521
4733
|
/**
|
|
4522
4734
|
* Handles dragging collision.
|
|
4523
4735
|
* @param {MouseEvent|Touch} event - The drag event.
|
|
4524
4736
|
*/
|
|
4525
4737
|
checkDragCollision(event) {
|
|
4526
|
-
const {
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4738
|
+
const { collidedElements } = this.execCollision(event);
|
|
4739
|
+
const first = collidedElements[0] || null;
|
|
4740
|
+
|
|
4741
|
+
// Removes old marking if necessary
|
|
4742
|
+
if (this.#lastCollision && !collidedElements.includes(this.#lastCollision)) {
|
|
4743
|
+
this.#removeCollision();
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
// Adds Marking for All Colluded
|
|
4747
|
+
collidedElements.forEach((el) => this.#addCollision(el));
|
|
4748
|
+
|
|
4749
|
+
// Removes markings from who no longer collided
|
|
4750
|
+
this.#collidables.forEach((el) => {
|
|
4751
|
+
if (!collidedElements.includes(el)) {
|
|
4752
|
+
el.classList.remove(this.#classDragCollision);
|
|
4530
4753
|
}
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
this.#
|
|
4754
|
+
});
|
|
4755
|
+
|
|
4756
|
+
if (
|
|
4757
|
+
navigator.vibrate &&
|
|
4758
|
+
Array.isArray(this.#vibration.collide) &&
|
|
4759
|
+
collidedElements.length > 0
|
|
4760
|
+
) {
|
|
4761
|
+
navigator.vibrate(this.#vibration.collide);
|
|
4536
4762
|
}
|
|
4763
|
+
|
|
4764
|
+
this.#lastCollision = first;
|
|
4537
4765
|
}
|
|
4538
4766
|
|
|
4539
4767
|
/**
|
|
@@ -4580,37 +4808,48 @@ class TinyDragger {
|
|
|
4580
4808
|
/**
|
|
4581
4809
|
* Handles the collision of a drag.
|
|
4582
4810
|
* @param {MouseEvent|Touch} event - The release event.
|
|
4583
|
-
* @returns {{ inJail: boolean;
|
|
4811
|
+
* @returns {{ inJail: boolean; collidedElements: (HTMLElement | null)[] }}
|
|
4584
4812
|
*/
|
|
4585
4813
|
execCollision(event) {
|
|
4586
|
-
if (this.#destroyed || !this.#dragProxy) return { inJail: false,
|
|
4814
|
+
if (this.#destroyed || !this.#dragProxy) return { inJail: false, collidedElements: [] };
|
|
4587
4815
|
|
|
4588
|
-
let
|
|
4816
|
+
let collidedElements = [];
|
|
4589
4817
|
let inJail = true;
|
|
4590
4818
|
const jailRect = this.#jail?.getBoundingClientRect();
|
|
4819
|
+
|
|
4591
4820
|
if (this.#collisionByMouse) {
|
|
4592
4821
|
const x = event.clientX;
|
|
4593
4822
|
const y = event.clientY;
|
|
4823
|
+
|
|
4594
4824
|
if (this.#dropInJailOnly && this.#jail && jailRect) {
|
|
4595
4825
|
inJail =
|
|
4596
4826
|
x >= jailRect.left && x <= jailRect.right && y >= jailRect.top && y <= jailRect.bottom;
|
|
4597
4827
|
}
|
|
4598
4828
|
|
|
4599
|
-
|
|
4829
|
+
collidedElements = inJail
|
|
4830
|
+
? this.#multiCollision
|
|
4831
|
+
? this.getAllCollidedElements(x, y)
|
|
4832
|
+
: [this.getCollidedElement(x, y)].filter(Boolean)
|
|
4833
|
+
: [];
|
|
4600
4834
|
} else {
|
|
4601
|
-
const
|
|
4835
|
+
const rect = this.#dragProxy.getBoundingClientRect();
|
|
4836
|
+
|
|
4602
4837
|
if (this.#dropInJailOnly && this.#jail && jailRect) {
|
|
4603
4838
|
inJail =
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4839
|
+
rect.left >= jailRect.left &&
|
|
4840
|
+
rect.right <= jailRect.right &&
|
|
4841
|
+
rect.top >= jailRect.top &&
|
|
4842
|
+
rect.bottom <= jailRect.bottom;
|
|
4608
4843
|
}
|
|
4609
4844
|
|
|
4610
|
-
|
|
4845
|
+
collidedElements = inJail
|
|
4846
|
+
? this.#multiCollision
|
|
4847
|
+
? this.getAllCollidedElementsByRect(rect)
|
|
4848
|
+
: [this.getCollidedElementByRect(rect)].filter(Boolean)
|
|
4849
|
+
: [];
|
|
4611
4850
|
}
|
|
4612
4851
|
|
|
4613
|
-
return { inJail,
|
|
4852
|
+
return { inJail, collidedElements };
|
|
4614
4853
|
}
|
|
4615
4854
|
|
|
4616
4855
|
/**
|
|
@@ -4633,7 +4872,7 @@ class TinyDragger {
|
|
|
4633
4872
|
|
|
4634
4873
|
document.removeEventListener('touchmove', this._onTouchMove);
|
|
4635
4874
|
document.removeEventListener('touchend', this._onTouchEnd);
|
|
4636
|
-
const {
|
|
4875
|
+
const { collidedElements } = this.execCollision(event);
|
|
4637
4876
|
|
|
4638
4877
|
if (navigator.vibrate && Array.isArray(this.#vibration.end)) {
|
|
4639
4878
|
navigator.vibrate(this.#vibration.end);
|
|
@@ -4646,7 +4885,7 @@ class TinyDragger {
|
|
|
4646
4885
|
this.#dragProxy = null;
|
|
4647
4886
|
}
|
|
4648
4887
|
|
|
4649
|
-
if (this.#lastCollision) this.#
|
|
4888
|
+
if (this.#lastCollision) this.#removeCollision();
|
|
4650
4889
|
this.#lastCollision = null;
|
|
4651
4890
|
|
|
4652
4891
|
this.#target.classList.remove(this.#dragHiddenClass);
|
|
@@ -4657,13 +4896,50 @@ class TinyDragger {
|
|
|
4657
4896
|
|
|
4658
4897
|
const dropEvent = new CustomEvent('drop', {
|
|
4659
4898
|
detail: {
|
|
4660
|
-
|
|
4899
|
+
targets: collidedElements,
|
|
4900
|
+
first: collidedElements[0] || null,
|
|
4661
4901
|
},
|
|
4662
4902
|
});
|
|
4663
|
-
|
|
4664
4903
|
this.#target.dispatchEvent(dropEvent);
|
|
4665
4904
|
}
|
|
4666
4905
|
|
|
4906
|
+
/**
|
|
4907
|
+
* Checks if the provided element intersects with the given bounding rectangle.
|
|
4908
|
+
*
|
|
4909
|
+
* @param {HTMLElement} el - The element to test for collision.
|
|
4910
|
+
* @param {DOMRect} rect - The bounding rectangle to check against.
|
|
4911
|
+
* @returns {boolean} True if the element intersects with the rectangle.
|
|
4912
|
+
*/
|
|
4913
|
+
#getCollidedElementByRect(el, rect) {
|
|
4914
|
+
const elRect = el.getBoundingClientRect();
|
|
4915
|
+
return !(
|
|
4916
|
+
rect.right < elRect.left ||
|
|
4917
|
+
rect.left > elRect.right ||
|
|
4918
|
+
rect.bottom < elRect.top ||
|
|
4919
|
+
rect.top > elRect.bottom
|
|
4920
|
+
);
|
|
4921
|
+
}
|
|
4922
|
+
|
|
4923
|
+
/**
|
|
4924
|
+
* Returns all elements currently colliding with the given rectangle.
|
|
4925
|
+
*
|
|
4926
|
+
* @param {DOMRect} rect - Bounding rectangle of the dragged proxy.
|
|
4927
|
+
* @returns {HTMLElement[]} A list of all collided elements.
|
|
4928
|
+
* @throws {Error} If the input is not a valid DOMRect with numeric bounds.
|
|
4929
|
+
*/
|
|
4930
|
+
getAllCollidedElementsByRect(rect) {
|
|
4931
|
+
this.#checkDestroy();
|
|
4932
|
+
if (
|
|
4933
|
+
!(rect instanceof DOMRect) ||
|
|
4934
|
+
typeof rect.left !== 'number' ||
|
|
4935
|
+
typeof rect.right !== 'number' ||
|
|
4936
|
+
typeof rect.top !== 'number' ||
|
|
4937
|
+
typeof rect.bottom !== 'number'
|
|
4938
|
+
)
|
|
4939
|
+
throw new Error('getCollidedElementByRect expects a valid DOMRect object.');
|
|
4940
|
+
return this.#collidables.filter((el) => this.#getCollidedElementByRect(el, rect));
|
|
4941
|
+
}
|
|
4942
|
+
|
|
4667
4943
|
/**
|
|
4668
4944
|
* Detects collision based on rectangle intersection.
|
|
4669
4945
|
* @param {DOMRect} rect - Bounding rectangle of the dragged proxy.
|
|
@@ -4680,18 +4956,32 @@ class TinyDragger {
|
|
|
4680
4956
|
typeof rect.bottom !== 'number'
|
|
4681
4957
|
)
|
|
4682
4958
|
throw new Error('getCollidedElementByRect expects a valid DOMRect object.');
|
|
4959
|
+
return this.#collidables.find((el) => this.#getCollidedElementByRect(el, rect)) || null;
|
|
4960
|
+
}
|
|
4683
4961
|
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4962
|
+
/**
|
|
4963
|
+
* Checks whether a given (x, y) coordinate is inside the bounding rectangle of an element.
|
|
4964
|
+
*
|
|
4965
|
+
* @param {HTMLElement} el - The element to test for collision.
|
|
4966
|
+
* @param {number} x - Horizontal screen coordinate.
|
|
4967
|
+
* @param {number} y - Vertical screen coordinate.
|
|
4968
|
+
* @returns {boolean} True if the point is within the element's bounds.
|
|
4969
|
+
*/
|
|
4970
|
+
#getCollidedElement(el, x, y) {
|
|
4971
|
+
const rect = el.getBoundingClientRect();
|
|
4972
|
+
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
4973
|
+
}
|
|
4974
|
+
|
|
4975
|
+
/**
|
|
4976
|
+
* @param {number} x - Horizontal screen coordinate.
|
|
4977
|
+
* @param {number} y - Vertical screen coordinate.
|
|
4978
|
+
* @returns {HTMLElement[]} The collided element or null.
|
|
4979
|
+
*/
|
|
4980
|
+
getAllCollidedElements(x, y) {
|
|
4981
|
+
this.#checkDestroy();
|
|
4982
|
+
if (typeof x !== 'number' || typeof y !== 'number')
|
|
4983
|
+
throw new Error('getCollidedElement expects numeric x and y coordinates.');
|
|
4984
|
+
return this.#collidables.filter((el) => this.#getCollidedElement(el, x, y));
|
|
4695
4985
|
}
|
|
4696
4986
|
|
|
4697
4987
|
/**
|
|
@@ -4704,13 +4994,7 @@ class TinyDragger {
|
|
|
4704
4994
|
this.#checkDestroy();
|
|
4705
4995
|
if (typeof x !== 'number' || typeof y !== 'number')
|
|
4706
4996
|
throw new Error('getCollidedElement expects numeric x and y coordinates.');
|
|
4707
|
-
|
|
4708
|
-
return (
|
|
4709
|
-
this.#collidables.find((el) => {
|
|
4710
|
-
const rect = el.getBoundingClientRect();
|
|
4711
|
-
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
4712
|
-
}) || null
|
|
4713
|
-
);
|
|
4997
|
+
return this.#collidables.find((el) => this.#getCollidedElement(el, x, y)) || null;
|
|
4714
4998
|
}
|
|
4715
4999
|
|
|
4716
5000
|
/**
|
|
@@ -4960,7 +5244,7 @@ class TinyDragger {
|
|
|
4960
5244
|
document.removeEventListener('touchmove', this._onTouchMove);
|
|
4961
5245
|
document.removeEventListener('touchend', this._onTouchEnd);
|
|
4962
5246
|
|
|
4963
|
-
if (this.#lastCollision) this.#
|
|
5247
|
+
if (this.#lastCollision) this.#removeCollision();
|
|
4964
5248
|
if (this.#dragProxy) {
|
|
4965
5249
|
this.#dragProxy.remove();
|
|
4966
5250
|
this.#dragProxy = null;
|
|
@@ -4998,6 +5282,10 @@ class TinyDragger {
|
|
|
4998
5282
|
|
|
4999
5283
|
|
|
5000
5284
|
|
|
5285
|
+
|
|
5286
|
+
|
|
5287
|
+
|
|
5288
|
+
|
|
5001
5289
|
|
|
5002
5290
|
|
|
5003
5291
|
|