@lvce-editor/explorer-view 2.11.0 → 2.13.0
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/explorerViewWorkerMain.js +194 -158
- package/package.json +1 -1
|
@@ -861,46 +861,6 @@ const WebWorkerRpcClient = {
|
|
|
861
861
|
create: create$1
|
|
862
862
|
};
|
|
863
863
|
|
|
864
|
-
const RE_CHARACTERS = /^[a-zA-Z.-]+$/;
|
|
865
|
-
const compareStringNumeric = (a, b) => {
|
|
866
|
-
if (RE_CHARACTERS.test(a) && RE_CHARACTERS.test(b)) {
|
|
867
|
-
return a < b ? -1 : 1;
|
|
868
|
-
}
|
|
869
|
-
return a.localeCompare(b, 'en', {
|
|
870
|
-
numeric: true
|
|
871
|
-
});
|
|
872
|
-
};
|
|
873
|
-
|
|
874
|
-
const BlockDevice = 1;
|
|
875
|
-
const CharacterDevice = 2;
|
|
876
|
-
const Directory = 3;
|
|
877
|
-
const DirectoryExpanded = 4;
|
|
878
|
-
const DirectoryExpanding = 5;
|
|
879
|
-
const File = 7;
|
|
880
|
-
const Socket = 8;
|
|
881
|
-
const Symlink = 9;
|
|
882
|
-
const SymLinkFile = 10;
|
|
883
|
-
const SymLinkFolder = 11;
|
|
884
|
-
const Unknown = 12;
|
|
885
|
-
|
|
886
|
-
const priorityMapFoldersFirst = {
|
|
887
|
-
[Directory]: 1,
|
|
888
|
-
[SymLinkFolder]: 1,
|
|
889
|
-
[File]: 0,
|
|
890
|
-
[SymLinkFile]: 0,
|
|
891
|
-
[Unknown]: 0,
|
|
892
|
-
[Socket]: 0
|
|
893
|
-
};
|
|
894
|
-
const compareDirentType = (direntA, direntB) => {
|
|
895
|
-
return priorityMapFoldersFirst[direntB.type] - priorityMapFoldersFirst[direntA.type];
|
|
896
|
-
};
|
|
897
|
-
const compareDirentName = (direntA, direntB) => {
|
|
898
|
-
return compareStringNumeric(direntA.name, direntB.name);
|
|
899
|
-
};
|
|
900
|
-
const compareDirent = (direntA, direntB) => {
|
|
901
|
-
return compareDirentType(direntA, direntB) || compareDirentName(direntA, direntB);
|
|
902
|
-
};
|
|
903
|
-
|
|
904
864
|
const None$5 = 0;
|
|
905
865
|
const CreateFile = 1;
|
|
906
866
|
const CreateFolder = 2;
|
|
@@ -991,28 +951,140 @@ const fileOrFolderNameMustBeProvided = () => {
|
|
|
991
951
|
const List = 1;
|
|
992
952
|
const Input$1 = 2;
|
|
993
953
|
|
|
954
|
+
// TODO optimize this function to return the minimum number
|
|
955
|
+
// of visible items needed, e.g. when not scrolled 5 items with
|
|
956
|
+
// 20px fill 100px but when scrolled 6 items are needed
|
|
957
|
+
const getNumberOfVisibleItems = (listHeight, itemHeight) => {
|
|
958
|
+
return Math.ceil(listHeight / itemHeight) + 1;
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
const getExplorerMaxLineY = (minLineY, height, itemHeight, direntsLength) => {
|
|
962
|
+
const maxLineY = minLineY + Math.min(getNumberOfVisibleItems(height, itemHeight), direntsLength);
|
|
963
|
+
return maxLineY;
|
|
964
|
+
};
|
|
965
|
+
|
|
966
|
+
const getIconsCached = (dirents, fileIconCache) => {
|
|
967
|
+
return dirents.map(dirent => fileIconCache[dirent]);
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
const getMissingIconRequests = (dirents, fileIconCache) => {
|
|
971
|
+
const missingRequests = [];
|
|
972
|
+
for (const dirent of dirents) {
|
|
973
|
+
if (!(dirent.path in fileIconCache)) {
|
|
974
|
+
missingRequests.push({
|
|
975
|
+
type: dirent.type,
|
|
976
|
+
name: dirent.name,
|
|
977
|
+
path: dirent.path
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return missingRequests;
|
|
982
|
+
};
|
|
983
|
+
|
|
984
|
+
const BlockDevice = 1;
|
|
985
|
+
const CharacterDevice = 2;
|
|
986
|
+
const Directory = 3;
|
|
987
|
+
const DirectoryExpanded = 4;
|
|
988
|
+
const DirectoryExpanding = 5;
|
|
989
|
+
const File = 7;
|
|
990
|
+
const Socket = 8;
|
|
991
|
+
const Symlink = 9;
|
|
992
|
+
const SymLinkFile = 10;
|
|
993
|
+
const SymLinkFolder = 11;
|
|
994
|
+
const Unknown = 12;
|
|
995
|
+
|
|
996
|
+
const RendererWorker = 1;
|
|
997
|
+
|
|
998
|
+
const rpcs = Object.create(null);
|
|
999
|
+
const set$1 = (id, rpc) => {
|
|
1000
|
+
rpcs[id] = rpc;
|
|
1001
|
+
};
|
|
1002
|
+
const get$1 = id => {
|
|
1003
|
+
return rpcs[id];
|
|
1004
|
+
};
|
|
1005
|
+
|
|
1006
|
+
const invoke = (method, ...params) => {
|
|
1007
|
+
const rpc = get$1(RendererWorker);
|
|
1008
|
+
// @ts-ignore
|
|
1009
|
+
return rpc.invoke(method, ...params);
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
const requestFileIcons = async requests => {
|
|
1013
|
+
const promises = requests.map(request => request.type === File ? invoke('IconTheme.getFileIcon', {
|
|
1014
|
+
name: request.name
|
|
1015
|
+
}) : invoke('IconTheme.getFolderIcon', {
|
|
1016
|
+
name: request.name
|
|
1017
|
+
}));
|
|
1018
|
+
return Promise.all(promises);
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1021
|
+
const updateIconCache = (iconCache, missingRequests, newIcons) => {
|
|
1022
|
+
if (missingRequests.length === 0) {
|
|
1023
|
+
return iconCache;
|
|
1024
|
+
}
|
|
1025
|
+
const newFileIconCache = {
|
|
1026
|
+
...iconCache
|
|
1027
|
+
};
|
|
1028
|
+
for (let i = 0; i < missingRequests.length; i++) {
|
|
1029
|
+
const request = missingRequests[i];
|
|
1030
|
+
const icon = newIcons[i];
|
|
1031
|
+
newFileIconCache[request.path] = icon;
|
|
1032
|
+
}
|
|
1033
|
+
return newFileIconCache;
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
const getFileIcons = async (dirents, fileIconCache) => {
|
|
1037
|
+
const missingRequests = getMissingIconRequests(dirents, fileIconCache);
|
|
1038
|
+
const newIcons = await requestFileIcons(missingRequests);
|
|
1039
|
+
const newFileIconCache = updateIconCache(fileIconCache, missingRequests, newIcons);
|
|
1040
|
+
const paths = dirents.map(dirent => dirent.path);
|
|
1041
|
+
const icons = getIconsCached(paths, newFileIconCache);
|
|
1042
|
+
return {
|
|
1043
|
+
icons,
|
|
1044
|
+
newFileIconCache
|
|
1045
|
+
};
|
|
1046
|
+
};
|
|
1047
|
+
|
|
1048
|
+
const RE_CHARACTERS = /^[a-zA-Z.-]+$/;
|
|
1049
|
+
const compareStringNumeric = (a, b) => {
|
|
1050
|
+
if (RE_CHARACTERS.test(a) && RE_CHARACTERS.test(b)) {
|
|
1051
|
+
return a < b ? -1 : 1;
|
|
1052
|
+
}
|
|
1053
|
+
return a.localeCompare(b, 'en', {
|
|
1054
|
+
numeric: true
|
|
1055
|
+
});
|
|
1056
|
+
};
|
|
1057
|
+
|
|
1058
|
+
const priorityMapFoldersFirst = {
|
|
1059
|
+
[Directory]: 1,
|
|
1060
|
+
[SymLinkFolder]: 1,
|
|
1061
|
+
[File]: 0,
|
|
1062
|
+
[SymLinkFile]: 0,
|
|
1063
|
+
[Unknown]: 0,
|
|
1064
|
+
[Socket]: 0
|
|
1065
|
+
};
|
|
1066
|
+
const compareDirentType = (direntA, direntB) => {
|
|
1067
|
+
return priorityMapFoldersFirst[direntB.type] - priorityMapFoldersFirst[direntA.type];
|
|
1068
|
+
};
|
|
1069
|
+
const compareDirentName = (direntA, direntB) => {
|
|
1070
|
+
return compareStringNumeric(direntA.name, direntB.name);
|
|
1071
|
+
};
|
|
1072
|
+
const compareDirent = (direntA, direntB) => {
|
|
1073
|
+
return compareDirentType(direntA, direntB) || compareDirentName(direntA, direntB);
|
|
1074
|
+
};
|
|
1075
|
+
|
|
994
1076
|
const getParentFolder = (dirents, index, root) => {
|
|
995
1077
|
if (index < 0) {
|
|
996
1078
|
return root;
|
|
997
1079
|
}
|
|
998
1080
|
return dirents[index].path;
|
|
999
1081
|
};
|
|
1000
|
-
const
|
|
1082
|
+
const getNewDirentsAccept = async (state, newDirentType, createFn) => {
|
|
1001
1083
|
const {
|
|
1002
1084
|
focusedIndex,
|
|
1003
1085
|
editingValue
|
|
1004
1086
|
} = state;
|
|
1005
1087
|
const newFileName = editingValue;
|
|
1006
|
-
if (!newFileName) {
|
|
1007
|
-
// TODO show error message that file name must not be empty
|
|
1008
|
-
// below input box
|
|
1009
|
-
// await ErrorHandling.showErrorDialog(new Error('file name must not be empty'))
|
|
1010
|
-
const editingErrorMessage = fileOrFolderNameMustBeProvided();
|
|
1011
|
-
return {
|
|
1012
|
-
...state,
|
|
1013
|
-
editingErrorMessage
|
|
1014
|
-
};
|
|
1015
|
-
}
|
|
1016
1088
|
const parentFolder = getParentFolder(state.items, focusedIndex, state.root);
|
|
1017
1089
|
const absolutePath = [parentFolder, newFileName].join(state.pathSeparator);
|
|
1018
1090
|
// TODO better handle error
|
|
@@ -1021,7 +1093,10 @@ const acceptCreate = async (state, newDirentType, createFn) => {
|
|
|
1021
1093
|
} catch (error) {
|
|
1022
1094
|
console.error(new VError(error, `Failed to create file`));
|
|
1023
1095
|
// TODO display error
|
|
1024
|
-
return
|
|
1096
|
+
return {
|
|
1097
|
+
dirents: state.items,
|
|
1098
|
+
newFocusedIndex: state.focusedIndex
|
|
1099
|
+
};
|
|
1025
1100
|
}
|
|
1026
1101
|
const parentDirent = focusedIndex >= 0 ? state.items[focusedIndex] : {
|
|
1027
1102
|
depth: 0};
|
|
@@ -1073,34 +1148,54 @@ const acceptCreate = async (state, newDirentType, createFn) => {
|
|
|
1073
1148
|
// @ts-ignore
|
|
1074
1149
|
items.splice(insertIndex + 1, 0, newDirent);
|
|
1075
1150
|
const newDirents = [...items];
|
|
1076
|
-
|
|
1151
|
+
return {
|
|
1152
|
+
dirents: newDirents,
|
|
1153
|
+
newFocusedIndex: insertIndex + 1
|
|
1154
|
+
};
|
|
1155
|
+
};
|
|
1156
|
+
|
|
1157
|
+
const acceptCreate = async (state, newDirentType, createFn) => {
|
|
1158
|
+
const {
|
|
1159
|
+
editingValue,
|
|
1160
|
+
minLineY,
|
|
1161
|
+
height,
|
|
1162
|
+
itemHeight,
|
|
1163
|
+
fileIconCache
|
|
1164
|
+
} = state;
|
|
1165
|
+
const newFileName = editingValue;
|
|
1166
|
+
if (!newFileName) {
|
|
1167
|
+
// TODO show error message that file name must not be empty
|
|
1168
|
+
// below input box
|
|
1169
|
+
// await ErrorHandling.showErrorDialog(new Error('file name must not be empty'))
|
|
1170
|
+
const editingErrorMessage = fileOrFolderNameMustBeProvided();
|
|
1171
|
+
return {
|
|
1172
|
+
...state,
|
|
1173
|
+
editingErrorMessage
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
const {
|
|
1177
|
+
dirents,
|
|
1178
|
+
newFocusedIndex
|
|
1179
|
+
} = await getNewDirentsAccept(state, newDirentType, createFn);
|
|
1180
|
+
const maxLineY = getExplorerMaxLineY(minLineY, height, itemHeight, dirents.length);
|
|
1181
|
+
const visible = dirents.slice(minLineY, maxLineY);
|
|
1182
|
+
const {
|
|
1183
|
+
icons,
|
|
1184
|
+
newFileIconCache
|
|
1185
|
+
} = await getFileIcons(visible, fileIconCache);
|
|
1077
1186
|
return {
|
|
1078
1187
|
...state,
|
|
1079
|
-
items:
|
|
1188
|
+
items: dirents,
|
|
1080
1189
|
editingIndex: -1,
|
|
1081
|
-
focusedIndex:
|
|
1190
|
+
focusedIndex: newFocusedIndex,
|
|
1082
1191
|
editingType: None$5,
|
|
1083
|
-
maxLineY
|
|
1084
|
-
focus: List
|
|
1192
|
+
maxLineY,
|
|
1193
|
+
focus: List,
|
|
1194
|
+
icons,
|
|
1195
|
+
fileIconCache: newFileIconCache
|
|
1085
1196
|
};
|
|
1086
1197
|
};
|
|
1087
1198
|
|
|
1088
|
-
const RendererWorker = 1;
|
|
1089
|
-
|
|
1090
|
-
const rpcs = Object.create(null);
|
|
1091
|
-
const set$1 = (id, rpc) => {
|
|
1092
|
-
rpcs[id] = rpc;
|
|
1093
|
-
};
|
|
1094
|
-
const get$1 = id => {
|
|
1095
|
-
return rpcs[id];
|
|
1096
|
-
};
|
|
1097
|
-
|
|
1098
|
-
const invoke = (method, ...params) => {
|
|
1099
|
-
const rpc = get$1(RendererWorker);
|
|
1100
|
-
// @ts-ignore
|
|
1101
|
-
return rpc.invoke(method, ...params);
|
|
1102
|
-
};
|
|
1103
|
-
|
|
1104
1199
|
const remove = async dirent => {
|
|
1105
1200
|
return invoke('FileSystem.remove', dirent);
|
|
1106
1201
|
};
|
|
@@ -1263,9 +1358,8 @@ const acceptRename = async state => {
|
|
|
1263
1358
|
const oldParentPath = dirname(pathSeparator, oldAbsolutePath);
|
|
1264
1359
|
const newAbsolutePath = [oldParentPath, editingValue].join(pathSeparator);
|
|
1265
1360
|
await rename(oldAbsolutePath, newAbsolutePath);
|
|
1266
|
-
} catch {
|
|
1267
|
-
|
|
1268
|
-
// await ErrorHandling.showErrorDialog(error)
|
|
1361
|
+
} catch (error) {
|
|
1362
|
+
console.error(new VError(error, `Failed to rename file`));
|
|
1269
1363
|
return state;
|
|
1270
1364
|
}
|
|
1271
1365
|
const {
|
|
@@ -1422,7 +1516,8 @@ const create2 = (uid, uri, x, y, width, height, args, parentUid, platform = 0) =
|
|
|
1422
1516
|
icons: [],
|
|
1423
1517
|
platform,
|
|
1424
1518
|
focus: 0,
|
|
1425
|
-
editingErrorMessage: ''
|
|
1519
|
+
editingErrorMessage: '',
|
|
1520
|
+
inputSource: 0
|
|
1426
1521
|
};
|
|
1427
1522
|
set(uid, state, state);
|
|
1428
1523
|
};
|
|
@@ -1458,7 +1553,8 @@ const create = (id, uri, x, y, width, height, args, parentUid, platform = 0) =>
|
|
|
1458
1553
|
icons: [],
|
|
1459
1554
|
platform,
|
|
1460
1555
|
focus: 0,
|
|
1461
|
-
editingErrorMessage: ''
|
|
1556
|
+
editingErrorMessage: '',
|
|
1557
|
+
inputSource: 0
|
|
1462
1558
|
};
|
|
1463
1559
|
set(state.uid, state, state);
|
|
1464
1560
|
return state;
|
|
@@ -1635,72 +1731,6 @@ const getChildDirents = async (pathSeparator, parentDirent, excluded = []) => {
|
|
|
1635
1731
|
return displayDirents;
|
|
1636
1732
|
};
|
|
1637
1733
|
|
|
1638
|
-
// TODO optimize this function to return the minimum number
|
|
1639
|
-
// of visible items needed, e.g. when not scrolled 5 items with
|
|
1640
|
-
// 20px fill 100px but when scrolled 6 items are needed
|
|
1641
|
-
const getNumberOfVisibleItems = (listHeight, itemHeight) => {
|
|
1642
|
-
return Math.ceil(listHeight / itemHeight) + 1;
|
|
1643
|
-
};
|
|
1644
|
-
|
|
1645
|
-
const getExplorerMaxLineY = (minLineY, height, itemHeight, direntsLength) => {
|
|
1646
|
-
const maxLineY = minLineY + Math.min(getNumberOfVisibleItems(height, itemHeight), direntsLength);
|
|
1647
|
-
return maxLineY;
|
|
1648
|
-
};
|
|
1649
|
-
|
|
1650
|
-
const getIconsCached = (dirents, fileIconCache) => {
|
|
1651
|
-
return dirents.map(dirent => fileIconCache[dirent]);
|
|
1652
|
-
};
|
|
1653
|
-
|
|
1654
|
-
const getMissingIconRequests = (dirents, fileIconCache) => {
|
|
1655
|
-
const missingRequests = [];
|
|
1656
|
-
for (const dirent of dirents) {
|
|
1657
|
-
if (!(dirent.path in fileIconCache)) {
|
|
1658
|
-
missingRequests.push({
|
|
1659
|
-
type: dirent.type,
|
|
1660
|
-
name: dirent.name,
|
|
1661
|
-
path: dirent.path
|
|
1662
|
-
});
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
return missingRequests;
|
|
1666
|
-
};
|
|
1667
|
-
|
|
1668
|
-
const requestFileIcons = async requests => {
|
|
1669
|
-
const promises = requests.map(request => request.type === File ? invoke('IconTheme.getFileIcon', {
|
|
1670
|
-
name: request.name
|
|
1671
|
-
}) : invoke('IconTheme.getFolderIcon', {
|
|
1672
|
-
name: request.name
|
|
1673
|
-
}));
|
|
1674
|
-
return Promise.all(promises);
|
|
1675
|
-
};
|
|
1676
|
-
|
|
1677
|
-
const updateIconCache = (iconCache, missingRequests, newIcons) => {
|
|
1678
|
-
if (missingRequests.length === 0) {
|
|
1679
|
-
return iconCache;
|
|
1680
|
-
}
|
|
1681
|
-
const newFileIconCache = {
|
|
1682
|
-
...iconCache
|
|
1683
|
-
};
|
|
1684
|
-
for (let i = 0; i < missingRequests.length; i++) {
|
|
1685
|
-
const request = missingRequests[i];
|
|
1686
|
-
const icon = newIcons[i];
|
|
1687
|
-
newFileIconCache[request.path] = icon;
|
|
1688
|
-
}
|
|
1689
|
-
return newFileIconCache;
|
|
1690
|
-
};
|
|
1691
|
-
|
|
1692
|
-
const getFileIcons = async (dirents, fileIconCache) => {
|
|
1693
|
-
const missingRequests = getMissingIconRequests(dirents, fileIconCache);
|
|
1694
|
-
const newIcons = await requestFileIcons(missingRequests);
|
|
1695
|
-
const newFileIconCache = updateIconCache(fileIconCache, missingRequests, newIcons);
|
|
1696
|
-
const paths = dirents.map(dirent => dirent.path);
|
|
1697
|
-
const icons = getIconsCached(paths, newFileIconCache);
|
|
1698
|
-
return {
|
|
1699
|
-
icons,
|
|
1700
|
-
newFileIconCache
|
|
1701
|
-
};
|
|
1702
|
-
};
|
|
1703
|
-
|
|
1704
1734
|
const expandAll = async state => {
|
|
1705
1735
|
const {
|
|
1706
1736
|
items,
|
|
@@ -3670,27 +3700,31 @@ const getFileIconVirtualDom = icon => {
|
|
|
3670
3700
|
};
|
|
3671
3701
|
};
|
|
3672
3702
|
|
|
3673
|
-
const label = {
|
|
3674
|
-
type: Div,
|
|
3675
|
-
className: Label,
|
|
3676
|
-
childCount: 1
|
|
3677
|
-
};
|
|
3678
3703
|
const getClassName$1 = hasEditingError => {
|
|
3679
3704
|
if (hasEditingError) {
|
|
3680
3705
|
return mergeClassNames(InputBox, InputValidationError);
|
|
3681
3706
|
}
|
|
3682
3707
|
return InputBox;
|
|
3683
3708
|
};
|
|
3709
|
+
const getInputDom = hasEditingError => {
|
|
3710
|
+
return [{
|
|
3711
|
+
type: Input,
|
|
3712
|
+
className: getClassName$1(hasEditingError),
|
|
3713
|
+
id: 'ExplorerInput',
|
|
3714
|
+
onInput: HandleEditingInput,
|
|
3715
|
+
childCount: 0,
|
|
3716
|
+
name: ExplorerInput
|
|
3717
|
+
}];
|
|
3718
|
+
};
|
|
3719
|
+
|
|
3720
|
+
const label = {
|
|
3721
|
+
type: Div,
|
|
3722
|
+
className: Label,
|
|
3723
|
+
childCount: 1
|
|
3724
|
+
};
|
|
3684
3725
|
const getInputOrLabelDom = (isEditing, hasEditingError, name) => {
|
|
3685
3726
|
if (isEditing) {
|
|
3686
|
-
return
|
|
3687
|
-
type: Input,
|
|
3688
|
-
className: getClassName$1(hasEditingError),
|
|
3689
|
-
id: 'ExplorerInput',
|
|
3690
|
-
onInput: HandleEditingInput,
|
|
3691
|
-
childCount: 0,
|
|
3692
|
-
name: ExplorerInput
|
|
3693
|
-
}];
|
|
3727
|
+
return getInputDom(hasEditingError);
|
|
3694
3728
|
}
|
|
3695
3729
|
return [label, text(name)];
|
|
3696
3730
|
};
|
|
@@ -4356,7 +4390,9 @@ const terminate = () => {
|
|
|
4356
4390
|
globalThis.close();
|
|
4357
4391
|
};
|
|
4358
4392
|
|
|
4359
|
-
const
|
|
4393
|
+
const User = 1;
|
|
4394
|
+
|
|
4395
|
+
const updateEditingValue = (state, value, inputSource = User) => {
|
|
4360
4396
|
const editingIcon = '';
|
|
4361
4397
|
return {
|
|
4362
4398
|
...state,
|