mindoodb 0.0.1
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 +263 -0
- package/dist/appendonlystores/InMemoryContentAddressedStoreFactory.d.ts +5 -0
- package/dist/appendonlystores/InMemoryContentAddressedStoreFactory.d.ts.map +1 -0
- package/dist/appendonlystores/InMemoryContentAddressedStoreFactory.js +17 -0
- package/dist/appendonlystores/InMemoryContentAddressedStoreFactory.js.map +1 -0
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +111 -0
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -0
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +237 -0
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -0
- package/dist/appendonlystores/network/HttpTransport.d.ts +78 -0
- package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -0
- package/dist/appendonlystores/network/HttpTransport.js +356 -0
- package/dist/appendonlystores/network/HttpTransport.js.map +1 -0
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +131 -0
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -0
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +248 -0
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -0
- package/dist/appendonlystores/network/index.d.ts +8 -0
- package/dist/appendonlystores/network/index.d.ts.map +1 -0
- package/dist/appendonlystores/network/index.js +21 -0
- package/dist/appendonlystores/network/index.js.map +1 -0
- package/dist/browser/crypto/BrowserCryptoAdapter.d.ts +14 -0
- package/dist/browser/crypto/BrowserCryptoAdapter.d.ts.map +1 -0
- package/dist/browser/crypto/BrowserCryptoAdapter.js +30 -0
- package/dist/browser/crypto/BrowserCryptoAdapter.js.map +1 -0
- package/dist/browser/index.d.ts +3 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +26 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/core/BaseMindooDB.d.ts +182 -0
- package/dist/core/BaseMindooDB.d.ts.map +1 -0
- package/dist/core/BaseMindooDB.js +1701 -0
- package/dist/core/BaseMindooDB.js.map +1 -0
- package/dist/core/BaseMindooTenant.d.ts +155 -0
- package/dist/core/BaseMindooTenant.d.ts.map +1 -0
- package/dist/core/BaseMindooTenant.js +673 -0
- package/dist/core/BaseMindooTenant.js.map +1 -0
- package/dist/core/BaseMindooTenantDirectory.d.ts +99 -0
- package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -0
- package/dist/core/BaseMindooTenantDirectory.js +776 -0
- package/dist/core/BaseMindooTenantDirectory.js.map +1 -0
- package/dist/core/BaseMindooTenantFactory.d.ts +91 -0
- package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -0
- package/dist/core/BaseMindooTenantFactory.js +297 -0
- package/dist/core/BaseMindooTenantFactory.js.map +1 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts +111 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts.map +1 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js +293 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js.map +1 -0
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts +78 -0
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -0
- package/dist/core/appendonlystores/network/AuthenticationService.js +297 -0
- package/dist/core/appendonlystores/network/AuthenticationService.js.map +1 -0
- package/dist/core/appendonlystores/network/NetworkTransport.d.ts +174 -0
- package/dist/core/appendonlystores/network/NetworkTransport.d.ts.map +1 -0
- package/dist/core/appendonlystores/network/NetworkTransport.js +3 -0
- package/dist/core/appendonlystores/network/NetworkTransport.js.map +1 -0
- package/dist/core/appendonlystores/network/types.d.ts +135 -0
- package/dist/core/appendonlystores/network/types.d.ts.map +1 -0
- package/dist/core/appendonlystores/network/types.js +35 -0
- package/dist/core/appendonlystores/network/types.js.map +1 -0
- package/dist/core/appendonlystores/types.d.ts +157 -0
- package/dist/core/appendonlystores/types.d.ts.map +1 -0
- package/dist/core/appendonlystores/types.js +3 -0
- package/dist/core/appendonlystores/types.js.map +1 -0
- package/dist/core/crypto/CryptoAdapter.d.ts +19 -0
- package/dist/core/crypto/CryptoAdapter.d.ts.map +1 -0
- package/dist/core/crypto/CryptoAdapter.js +3 -0
- package/dist/core/crypto/CryptoAdapter.js.map +1 -0
- package/dist/core/crypto/MindooDocSigner.d.ts +106 -0
- package/dist/core/crypto/MindooDocSigner.d.ts.map +1 -0
- package/dist/core/crypto/MindooDocSigner.js +192 -0
- package/dist/core/crypto/MindooDocSigner.js.map +1 -0
- package/dist/core/crypto/RSAEncryption.d.ts +62 -0
- package/dist/core/crypto/RSAEncryption.d.ts.map +1 -0
- package/dist/core/crypto/RSAEncryption.js +167 -0
- package/dist/core/crypto/RSAEncryption.js.map +1 -0
- package/dist/core/errors.d.ts +10 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +17 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/index.d.ts +14 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +53 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/indexing/virtualviews/IViewEntryAccessCheck.d.ts +33 -0
- package/dist/core/indexing/virtualviews/IViewEntryAccessCheck.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/IViewEntryAccessCheck.js +27 -0
- package/dist/core/indexing/virtualviews/IViewEntryAccessCheck.js.map +1 -0
- package/dist/core/indexing/virtualviews/IVirtualViewDataProvider.d.ts +31 -0
- package/dist/core/indexing/virtualviews/IVirtualViewDataProvider.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/IVirtualViewDataProvider.js +3 -0
- package/dist/core/indexing/virtualviews/IVirtualViewDataProvider.js.map +1 -0
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts +52 -0
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js +106 -0
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js.map +1 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKey.d.ts +44 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKey.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKey.js +107 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKey.js.map +1 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKeyComparator.d.ts +28 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKeyComparator.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKeyComparator.js +133 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKeyComparator.js.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualView.d.ts +109 -0
- package/dist/core/indexing/virtualviews/VirtualView.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualView.js +504 -0
- package/dist/core/indexing/virtualviews/VirtualView.js.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewColumn.d.ts +59 -0
- package/dist/core/indexing/virtualviews/VirtualViewColumn.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewColumn.js +70 -0
- package/dist/core/indexing/virtualviews/VirtualViewColumn.js.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewDataChange.d.ts +49 -0
- package/dist/core/indexing/virtualviews/VirtualViewDataChange.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewDataChange.js +69 -0
- package/dist/core/indexing/virtualviews/VirtualViewDataChange.js.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts +121 -0
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.js +365 -0
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.js.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewFactory.d.ts +131 -0
- package/dist/core/indexing/virtualviews/VirtualViewFactory.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewFactory.js +236 -0
- package/dist/core/indexing/virtualviews/VirtualViewFactory.js.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewNavigator.d.ts +330 -0
- package/dist/core/indexing/virtualviews/VirtualViewNavigator.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewNavigator.js +1010 -0
- package/dist/core/indexing/virtualviews/VirtualViewNavigator.js.map +1 -0
- package/dist/core/indexing/virtualviews/index.d.ts +53 -0
- package/dist/core/indexing/virtualviews/index.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/index.js +89 -0
- package/dist/core/indexing/virtualviews/index.js.map +1 -0
- package/dist/core/indexing/virtualviews/types.d.ts +115 -0
- package/dist/core/indexing/virtualviews/types.d.ts.map +1 -0
- package/dist/core/indexing/virtualviews/types.js +175 -0
- package/dist/core/indexing/virtualviews/types.js.map +1 -0
- package/dist/core/keys/KeyBag.d.ts +122 -0
- package/dist/core/keys/KeyBag.d.ts.map +1 -0
- package/dist/core/keys/KeyBag.js +401 -0
- package/dist/core/keys/KeyBag.js.map +1 -0
- package/dist/core/types.d.ts +1004 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +10 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/userid/index.d.ts +53 -0
- package/dist/core/userid/index.d.ts.map +1 -0
- package/dist/core/userid/index.js +3 -0
- package/dist/core/userid/index.js.map +1 -0
- package/dist/core/utils/idGeneration.d.ts +109 -0
- package/dist/core/utils/idGeneration.d.ts.map +1 -0
- package/dist/core/utils/idGeneration.js +182 -0
- package/dist/core/utils/idGeneration.js.map +1 -0
- package/dist/core/utils/index.d.ts +5 -0
- package/dist/core/utils/index.d.ts.map +1 -0
- package/dist/core/utils/index.js +19 -0
- package/dist/core/utils/index.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/node/crypto/NodeCryptoAdapter.d.ts +16 -0
- package/dist/node/crypto/NodeCryptoAdapter.d.ts.map +1 -0
- package/dist/node/crypto/NodeCryptoAdapter.js +53 -0
- package/dist/node/crypto/NodeCryptoAdapter.js.map +1 -0
- package/dist/node/index.d.ts +3 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +26 -0
- package/dist/node/index.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,1010 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VirtualViewNavigator = void 0;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
/**
|
|
6
|
+
* Navigator for traversing a VirtualView tree structure.
|
|
7
|
+
* Handles expanded/collapsed states, selection, and access control.
|
|
8
|
+
*/
|
|
9
|
+
class VirtualViewNavigator {
|
|
10
|
+
constructor(view, topEntry, withCategories, withDocuments, accessCheck = null, dontShowEmptyCategories = false) {
|
|
11
|
+
/** Stack of traversal states for navigation */
|
|
12
|
+
this.currentEntryStack = [];
|
|
13
|
+
/** Selection state - if selectAll is true, this is a deselection list */
|
|
14
|
+
this.selectedOrDeselectedEntries = new Set();
|
|
15
|
+
this.selectAll = false;
|
|
16
|
+
/** Expansion state - if expandAllByDefault is true, this is a collapse list */
|
|
17
|
+
this.expandedOrCollapsedEntries = new Set();
|
|
18
|
+
this.expandAllByDefault = false;
|
|
19
|
+
this.expandLevel = 0;
|
|
20
|
+
this.view = view;
|
|
21
|
+
this.topEntry = topEntry;
|
|
22
|
+
this.withCategories = withCategories === types_1.WithCategories.YES;
|
|
23
|
+
this.withDocuments = withDocuments === types_1.WithDocuments.YES;
|
|
24
|
+
this.accessCheck = accessCheck;
|
|
25
|
+
this.dontShowEmptyCategories = dontShowEmptyCategories;
|
|
26
|
+
if (!this.withCategories && !this.withDocuments) {
|
|
27
|
+
throw new Error("Navigator must include categories, documents, or both");
|
|
28
|
+
}
|
|
29
|
+
// Initialize traversal at top entry
|
|
30
|
+
this.initializeTraversal();
|
|
31
|
+
}
|
|
32
|
+
initializeTraversal() {
|
|
33
|
+
this.currentEntryStack = [];
|
|
34
|
+
if (this.topEntry) {
|
|
35
|
+
this.currentEntryStack.push(this.createTraversalInfo(this.topEntry));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
createTraversalInfo(parentEntry) {
|
|
39
|
+
// Always get all child entries for traversal purposes
|
|
40
|
+
// Filtering happens when we return entries (getCurrentEntry)
|
|
41
|
+
const childEntries = parentEntry.getChildEntries();
|
|
42
|
+
return {
|
|
43
|
+
parentEntry,
|
|
44
|
+
withCategories: this.withCategories,
|
|
45
|
+
withDocuments: this.withDocuments,
|
|
46
|
+
childEntries,
|
|
47
|
+
currentIndex: -1, // Before first entry
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
getView() {
|
|
51
|
+
return this.view;
|
|
52
|
+
}
|
|
53
|
+
isDontShowEmptyCategories() {
|
|
54
|
+
return this.dontShowEmptyCategories;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Set a new root for navigation (restrict to subtree)
|
|
58
|
+
*/
|
|
59
|
+
setRoot(newRoot) {
|
|
60
|
+
this.topEntry = newRoot;
|
|
61
|
+
this.initializeTraversal();
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
// ===== Navigation Methods =====
|
|
65
|
+
/**
|
|
66
|
+
* Get the current entry at the cursor position
|
|
67
|
+
*/
|
|
68
|
+
getCurrentEntry() {
|
|
69
|
+
if (this.currentEntryStack.length === 0) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const info = this.currentEntryStack[this.currentEntryStack.length - 1];
|
|
73
|
+
if (info.currentIndex < 0 || info.currentIndex >= info.childEntries.length) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const entry = info.childEntries[info.currentIndex];
|
|
77
|
+
// Check visibility
|
|
78
|
+
if (!this.isVisible(entry)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
// Filter by type
|
|
82
|
+
if (entry.isCategory() && !this.withCategories) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (entry.isDocument() && !this.withDocuments) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return entry;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Move to the first entry
|
|
92
|
+
*/
|
|
93
|
+
gotoFirst() {
|
|
94
|
+
// Reset to top level
|
|
95
|
+
while (this.currentEntryStack.length > 1) {
|
|
96
|
+
this.currentEntryStack.pop();
|
|
97
|
+
}
|
|
98
|
+
const info = this.currentEntryStack[0];
|
|
99
|
+
if (!info || info.childEntries.length === 0) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
// Find first visible entry (raw visibility)
|
|
103
|
+
for (let i = 0; i < info.childEntries.length; i++) {
|
|
104
|
+
info.currentIndex = i;
|
|
105
|
+
if (this.isVisibleRaw(info.childEntries[i])) {
|
|
106
|
+
// Check if this matches our type filter
|
|
107
|
+
const entry = this.getCurrentEntry();
|
|
108
|
+
if (entry) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
// Entry doesn't match filter, continue to navigate into it or past it
|
|
112
|
+
return this.gotoNext();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Move to the last entry (taking expansion into account)
|
|
119
|
+
*/
|
|
120
|
+
gotoLast() {
|
|
121
|
+
// Reset to top level
|
|
122
|
+
while (this.currentEntryStack.length > 1) {
|
|
123
|
+
this.currentEntryStack.pop();
|
|
124
|
+
}
|
|
125
|
+
const info = this.currentEntryStack[0];
|
|
126
|
+
if (!info || info.childEntries.length === 0) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
// Find last visible entry
|
|
130
|
+
for (let i = info.childEntries.length - 1; i >= 0; i--) {
|
|
131
|
+
info.currentIndex = i;
|
|
132
|
+
if (this.isVisible(info.childEntries[i])) {
|
|
133
|
+
// Navigate to deepest expanded descendant
|
|
134
|
+
this.gotoDeepestExpandedDescendant(info.childEntries[i]);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Move to the next entry (respecting expand states)
|
|
142
|
+
*/
|
|
143
|
+
gotoNext() {
|
|
144
|
+
const currEntry = this.getCurrentEntryRaw();
|
|
145
|
+
if (!currEntry) {
|
|
146
|
+
// No current entry - try to find one by moving through the tree
|
|
147
|
+
if (this.gotoNextSibling()) {
|
|
148
|
+
// Check if this entry should be returned
|
|
149
|
+
const entry = this.getCurrentEntry();
|
|
150
|
+
if (entry)
|
|
151
|
+
return true;
|
|
152
|
+
// Keep searching
|
|
153
|
+
return this.gotoNext();
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
// If expanded and has children, go to first child
|
|
158
|
+
if (this.isExpanded(currEntry) && currEntry.getChildCount() > 0) {
|
|
159
|
+
const childInfo = this.createTraversalInfo(currEntry);
|
|
160
|
+
if (childInfo.childEntries.length > 0) {
|
|
161
|
+
childInfo.currentIndex = 0;
|
|
162
|
+
// Find first visible child (visibility check only, not type filter)
|
|
163
|
+
while (childInfo.currentIndex < childInfo.childEntries.length &&
|
|
164
|
+
!this.isVisibleRaw(childInfo.childEntries[childInfo.currentIndex])) {
|
|
165
|
+
childInfo.currentIndex++;
|
|
166
|
+
}
|
|
167
|
+
if (childInfo.currentIndex < childInfo.childEntries.length) {
|
|
168
|
+
this.currentEntryStack.push(childInfo);
|
|
169
|
+
// Check if this entry matches our filter
|
|
170
|
+
const entry = this.getCurrentEntry();
|
|
171
|
+
if (entry) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
// Entry doesn't match filter (e.g., it's a category but we want documents)
|
|
175
|
+
// Continue navigating
|
|
176
|
+
return this.gotoNext();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Try next sibling
|
|
181
|
+
if (this.gotoNextSiblingRaw()) {
|
|
182
|
+
// Check if this entry matches our filter
|
|
183
|
+
const entry = this.getCurrentEntry();
|
|
184
|
+
if (entry) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
// Keep searching
|
|
188
|
+
return this.gotoNext();
|
|
189
|
+
}
|
|
190
|
+
// Go up and try next sibling of parent
|
|
191
|
+
while (this.gotoParent()) {
|
|
192
|
+
if (this.gotoNextSiblingRaw()) {
|
|
193
|
+
// Check if this entry matches our filter
|
|
194
|
+
const entry = this.getCurrentEntry();
|
|
195
|
+
if (entry) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
// Keep searching
|
|
199
|
+
return this.gotoNext();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get the current entry without type filtering (for internal navigation)
|
|
206
|
+
*/
|
|
207
|
+
getCurrentEntryRaw() {
|
|
208
|
+
if (this.currentEntryStack.length === 0) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const info = this.currentEntryStack[this.currentEntryStack.length - 1];
|
|
212
|
+
if (info.currentIndex < 0 || info.currentIndex >= info.childEntries.length) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
return info.childEntries[info.currentIndex];
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Check visibility without type filtering
|
|
219
|
+
*/
|
|
220
|
+
isVisibleRaw(entry) {
|
|
221
|
+
// Check access control
|
|
222
|
+
if (this.accessCheck && !this.accessCheck.isVisible(this, entry)) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Move to next sibling without checking type filter
|
|
229
|
+
*/
|
|
230
|
+
gotoNextSiblingRaw() {
|
|
231
|
+
if (this.currentEntryStack.length === 0) {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
const info = this.currentEntryStack[this.currentEntryStack.length - 1];
|
|
235
|
+
// Find next visible entry
|
|
236
|
+
for (let i = info.currentIndex + 1; i < info.childEntries.length; i++) {
|
|
237
|
+
if (this.isVisibleRaw(info.childEntries[i])) {
|
|
238
|
+
info.currentIndex = i;
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Move to the previous entry (respecting expand states)
|
|
246
|
+
*/
|
|
247
|
+
gotoPrev() {
|
|
248
|
+
const currEntry = this.getCurrentEntry();
|
|
249
|
+
if (!currEntry) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
// Try previous sibling
|
|
253
|
+
if (this.gotoPrevSibling()) {
|
|
254
|
+
// Navigate to deepest expanded descendant of prev sibling
|
|
255
|
+
const prevEntry = this.getCurrentEntry();
|
|
256
|
+
if (prevEntry) {
|
|
257
|
+
this.gotoDeepestExpandedDescendant(prevEntry);
|
|
258
|
+
}
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
// Go up to parent
|
|
262
|
+
return this.gotoParent();
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Move to the next sibling
|
|
266
|
+
*/
|
|
267
|
+
gotoNextSibling() {
|
|
268
|
+
if (this.currentEntryStack.length === 0) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
const info = this.currentEntryStack[this.currentEntryStack.length - 1];
|
|
272
|
+
// Find next visible entry
|
|
273
|
+
for (let i = info.currentIndex + 1; i < info.childEntries.length; i++) {
|
|
274
|
+
if (this.isVisible(info.childEntries[i])) {
|
|
275
|
+
info.currentIndex = i;
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Move to the previous sibling
|
|
283
|
+
*/
|
|
284
|
+
gotoPrevSibling() {
|
|
285
|
+
if (this.currentEntryStack.length === 0) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
const info = this.currentEntryStack[this.currentEntryStack.length - 1];
|
|
289
|
+
// Find previous visible entry
|
|
290
|
+
for (let i = info.currentIndex - 1; i >= 0; i--) {
|
|
291
|
+
if (this.isVisible(info.childEntries[i])) {
|
|
292
|
+
info.currentIndex = i;
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Move to the parent entry
|
|
300
|
+
*/
|
|
301
|
+
gotoParent() {
|
|
302
|
+
if (this.currentEntryStack.length > 1) {
|
|
303
|
+
this.currentEntryStack.pop();
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Move to the first child of current entry
|
|
310
|
+
*/
|
|
311
|
+
gotoFirstChild() {
|
|
312
|
+
const currEntry = this.getCurrentEntry();
|
|
313
|
+
if (!currEntry) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
const childInfo = this.createTraversalInfo(currEntry);
|
|
317
|
+
if (childInfo.childEntries.length === 0) {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
// Find first visible child
|
|
321
|
+
for (let i = 0; i < childInfo.childEntries.length; i++) {
|
|
322
|
+
if (this.isVisible(childInfo.childEntries[i])) {
|
|
323
|
+
childInfo.currentIndex = i;
|
|
324
|
+
this.currentEntryStack.push(childInfo);
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Move to the last child of current entry
|
|
332
|
+
*/
|
|
333
|
+
gotoLastChild() {
|
|
334
|
+
const currEntry = this.getCurrentEntry();
|
|
335
|
+
if (!currEntry) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
const childInfo = this.createTraversalInfo(currEntry);
|
|
339
|
+
if (childInfo.childEntries.length === 0) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
// Find last visible child
|
|
343
|
+
for (let i = childInfo.childEntries.length - 1; i >= 0; i--) {
|
|
344
|
+
if (this.isVisible(childInfo.childEntries[i])) {
|
|
345
|
+
childInfo.currentIndex = i;
|
|
346
|
+
this.currentEntryStack.push(childInfo);
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
gotoDeepestExpandedDescendant(entry) {
|
|
353
|
+
if (entry.getChildCount() > 0 && this.isExpanded(entry)) {
|
|
354
|
+
const childInfo = this.createTraversalInfo(entry);
|
|
355
|
+
// Find last visible child
|
|
356
|
+
for (let i = childInfo.childEntries.length - 1; i >= 0; i--) {
|
|
357
|
+
if (this.isVisible(childInfo.childEntries[i])) {
|
|
358
|
+
childInfo.currentIndex = i;
|
|
359
|
+
this.currentEntryStack.push(childInfo);
|
|
360
|
+
this.gotoDeepestExpandedDescendant(childInfo.childEntries[i]);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Move to a specific position (e.g., "1.2.3")
|
|
368
|
+
*/
|
|
369
|
+
gotoPos(posStr) {
|
|
370
|
+
const pos = posStr.split(".").map(p => parseInt(p, 10));
|
|
371
|
+
return this.gotoPosArray(pos);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Move to a specific position array (e.g., [1, 2, 3])
|
|
375
|
+
*/
|
|
376
|
+
gotoPosArray(pos) {
|
|
377
|
+
// Reset to top level
|
|
378
|
+
this.initializeTraversal();
|
|
379
|
+
let currentInfo = this.currentEntryStack[0];
|
|
380
|
+
if (!currentInfo) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
for (let i = 0; i < pos.length; i++) {
|
|
384
|
+
const targetSiblingIndex = pos[i];
|
|
385
|
+
// Find entry with matching sibling index
|
|
386
|
+
let found = false;
|
|
387
|
+
for (let j = 0; j < currentInfo.childEntries.length; j++) {
|
|
388
|
+
const entry = currentInfo.childEntries[j];
|
|
389
|
+
if (entry.getSiblingIndex() === targetSiblingIndex && this.isVisible(entry)) {
|
|
390
|
+
currentInfo.currentIndex = j;
|
|
391
|
+
found = true;
|
|
392
|
+
// If more levels to go, push new traversal info
|
|
393
|
+
if (i < pos.length - 1) {
|
|
394
|
+
const nextInfo = this.createTraversalInfo(entry);
|
|
395
|
+
this.currentEntryStack.push(nextInfo);
|
|
396
|
+
currentInfo = nextInfo;
|
|
397
|
+
}
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (!found) {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Get the entry at a specific position without moving the cursor
|
|
409
|
+
*
|
|
410
|
+
* @param posStr Position string e.g. "1.2.3"
|
|
411
|
+
* @returns The entry at the position or null if not found
|
|
412
|
+
*/
|
|
413
|
+
getPos(posStr) {
|
|
414
|
+
const pos = posStr.split(".").map(p => parseInt(p, 10));
|
|
415
|
+
return this.getPosArray(pos);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Get the entry at a specific position array without moving the cursor
|
|
419
|
+
*
|
|
420
|
+
* @param pos Position array e.g. [1, 2, 3]
|
|
421
|
+
* @returns The entry at the position or null if not found
|
|
422
|
+
*/
|
|
423
|
+
getPosArray(pos) {
|
|
424
|
+
// Save current state
|
|
425
|
+
const savedStack = this.currentEntryStack.map(info => ({
|
|
426
|
+
...info,
|
|
427
|
+
childEntries: info.childEntries,
|
|
428
|
+
}));
|
|
429
|
+
// Navigate to position
|
|
430
|
+
const found = this.gotoPosArray(pos);
|
|
431
|
+
const entry = found ? this.getCurrentEntry() : null;
|
|
432
|
+
// Restore state
|
|
433
|
+
this.currentEntryStack = savedStack;
|
|
434
|
+
return entry;
|
|
435
|
+
}
|
|
436
|
+
// ===== Category Finding Methods =====
|
|
437
|
+
/**
|
|
438
|
+
* Find a category entry by path string (e.g., "Category1\\Category1.1")
|
|
439
|
+
* Navigates through the category tree from the top entry.
|
|
440
|
+
*
|
|
441
|
+
* @param category Category path with backslash separators
|
|
442
|
+
* @returns The category entry or null if not found
|
|
443
|
+
*/
|
|
444
|
+
findCategoryEntry(category) {
|
|
445
|
+
const categoryParts = category.split("\\");
|
|
446
|
+
return this.findCategoryEntryByParts(categoryParts);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Find a category entry by array of category parts
|
|
450
|
+
* Navigates through the category tree from the top entry.
|
|
451
|
+
*
|
|
452
|
+
* @param categoryParts Array of category values e.g. ["Category1", "Category1.1"]
|
|
453
|
+
* @returns The category entry or null if not found
|
|
454
|
+
*/
|
|
455
|
+
findCategoryEntryByParts(categoryParts) {
|
|
456
|
+
let currentEntry = this.topEntry;
|
|
457
|
+
for (const part of categoryParts) {
|
|
458
|
+
if (!currentEntry) {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
// Find matching subcategory
|
|
462
|
+
const matchingCategory = this.childCategoriesByKey(currentEntry, String(part), true, false)
|
|
463
|
+
.find(() => true); // Get first match
|
|
464
|
+
if (!matchingCategory) {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
currentEntry = matchingCategory;
|
|
468
|
+
}
|
|
469
|
+
return currentEntry;
|
|
470
|
+
}
|
|
471
|
+
// ===== Iteration Methods =====
|
|
472
|
+
/**
|
|
473
|
+
* Iterate forward through entries
|
|
474
|
+
*/
|
|
475
|
+
async *entriesForward(selectedOnly = types_1.SelectedOnly.NO) {
|
|
476
|
+
if (!this.gotoFirst()) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
do {
|
|
480
|
+
const entry = this.getCurrentEntry();
|
|
481
|
+
if (entry) {
|
|
482
|
+
if (selectedOnly === types_1.SelectedOnly.NO || this.isSelected(entry.origin, entry.docId)) {
|
|
483
|
+
yield entry;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
} while (selectedOnly === types_1.SelectedOnly.YES ? this.gotoNextSelected() : this.gotoNext());
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Iterate forward through entries starting from a specific position
|
|
490
|
+
*
|
|
491
|
+
* @param startPos Starting position string e.g. "1.2.3"
|
|
492
|
+
* @param selectedOnly Whether to only yield selected entries
|
|
493
|
+
*/
|
|
494
|
+
async *entriesForwardFromPosition(startPos, selectedOnly = types_1.SelectedOnly.NO) {
|
|
495
|
+
if (!this.gotoPos(startPos)) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
do {
|
|
499
|
+
const entry = this.getCurrentEntry();
|
|
500
|
+
if (entry) {
|
|
501
|
+
if (selectedOnly === types_1.SelectedOnly.NO || this.isSelected(entry.origin, entry.docId)) {
|
|
502
|
+
yield entry;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
} while (selectedOnly === types_1.SelectedOnly.YES ? this.gotoNextSelected() : this.gotoNext());
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Iterate backward through entries
|
|
509
|
+
*/
|
|
510
|
+
async *entriesBackward(selectedOnly = types_1.SelectedOnly.NO) {
|
|
511
|
+
if (!this.gotoLast()) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
do {
|
|
515
|
+
const entry = this.getCurrentEntry();
|
|
516
|
+
if (entry) {
|
|
517
|
+
if (selectedOnly === types_1.SelectedOnly.NO || this.isSelected(entry.origin, entry.docId)) {
|
|
518
|
+
yield entry;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
} while (selectedOnly === types_1.SelectedOnly.YES ? this.gotoPrevSelected() : this.gotoPrev());
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Move to next selected entry
|
|
525
|
+
*/
|
|
526
|
+
gotoNextSelected() {
|
|
527
|
+
while (this.gotoNext()) {
|
|
528
|
+
const entry = this.getCurrentEntry();
|
|
529
|
+
if (entry && this.isSelected(entry.origin, entry.docId)) {
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Move to previous selected entry
|
|
537
|
+
*/
|
|
538
|
+
gotoPrevSelected() {
|
|
539
|
+
while (this.gotoPrev()) {
|
|
540
|
+
const entry = this.getCurrentEntry();
|
|
541
|
+
if (entry && this.isSelected(entry.origin, entry.docId)) {
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
// ===== Visibility Check =====
|
|
548
|
+
isVisible(entry) {
|
|
549
|
+
// Check access control
|
|
550
|
+
if (this.accessCheck && !this.accessCheck.isVisible(this, entry)) {
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
// Check empty categories
|
|
554
|
+
if (this.dontShowEmptyCategories && entry.isCategory()) {
|
|
555
|
+
if (entry.getDescendantDocumentCount() === 0) {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
// ===== Selection Methods =====
|
|
562
|
+
/**
|
|
563
|
+
* Select an entry
|
|
564
|
+
*/
|
|
565
|
+
select(origin, docId, selectParentCategories = false) {
|
|
566
|
+
const key = (0, types_1.scopedDocIdKey)((0, types_1.createScopedDocId)(origin, docId));
|
|
567
|
+
if (this.selectAll) {
|
|
568
|
+
this.selectedOrDeselectedEntries.delete(key);
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
this.selectedOrDeselectedEntries.add(key);
|
|
572
|
+
}
|
|
573
|
+
if (selectParentCategories) {
|
|
574
|
+
const entries = this.view.getEntries(origin, docId);
|
|
575
|
+
for (const entry of entries) {
|
|
576
|
+
let parent = entry.getParent();
|
|
577
|
+
while (parent && !parent.isRoot()) {
|
|
578
|
+
const parentKey = (0, types_1.scopedDocIdKey)((0, types_1.createScopedDocId)(parent.origin, parent.docId));
|
|
579
|
+
if (this.selectAll) {
|
|
580
|
+
this.selectedOrDeselectedEntries.delete(parentKey);
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
this.selectedOrDeselectedEntries.add(parentKey);
|
|
584
|
+
}
|
|
585
|
+
parent = parent.getParent();
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return this;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Deselect an entry
|
|
593
|
+
*/
|
|
594
|
+
deselect(origin, docId) {
|
|
595
|
+
const key = (0, types_1.scopedDocIdKey)((0, types_1.createScopedDocId)(origin, docId));
|
|
596
|
+
if (this.selectAll) {
|
|
597
|
+
this.selectedOrDeselectedEntries.add(key);
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
this.selectedOrDeselectedEntries.delete(key);
|
|
601
|
+
}
|
|
602
|
+
return this;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Select all entries
|
|
606
|
+
*/
|
|
607
|
+
selectAllEntries() {
|
|
608
|
+
this.selectedOrDeselectedEntries.clear();
|
|
609
|
+
this.selectAll = true;
|
|
610
|
+
return this;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Deselect all entries
|
|
614
|
+
*/
|
|
615
|
+
deselectAllEntries() {
|
|
616
|
+
this.selectedOrDeselectedEntries.clear();
|
|
617
|
+
this.selectAll = false;
|
|
618
|
+
return this;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Check if an entry is selected
|
|
622
|
+
*/
|
|
623
|
+
isSelected(origin, docId) {
|
|
624
|
+
const key = (0, types_1.scopedDocIdKey)((0, types_1.createScopedDocId)(origin, docId));
|
|
625
|
+
if (this.selectAll) {
|
|
626
|
+
return !this.selectedOrDeselectedEntries.has(key);
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
return this.selectedOrDeselectedEntries.has(key);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
isSelectAllByDefault() {
|
|
633
|
+
return this.selectAll;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Returns whether all entries are deselected by default
|
|
637
|
+
*/
|
|
638
|
+
isDeselectAllByDefault() {
|
|
639
|
+
return !this.selectAll;
|
|
640
|
+
}
|
|
641
|
+
// ===== Expand/Collapse Methods =====
|
|
642
|
+
/**
|
|
643
|
+
* Expand an entry
|
|
644
|
+
*/
|
|
645
|
+
expand(origin, docId) {
|
|
646
|
+
const key = (0, types_1.scopedDocIdKey)((0, types_1.createScopedDocId)(origin, docId));
|
|
647
|
+
if (!this.expandAllByDefault) {
|
|
648
|
+
this.expandedOrCollapsedEntries.add(key);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
this.expandedOrCollapsedEntries.delete(key);
|
|
652
|
+
}
|
|
653
|
+
return this;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Collapse an entry
|
|
657
|
+
*/
|
|
658
|
+
collapse(origin, docId) {
|
|
659
|
+
const key = (0, types_1.scopedDocIdKey)((0, types_1.createScopedDocId)(origin, docId));
|
|
660
|
+
if (this.expandAllByDefault) {
|
|
661
|
+
this.expandedOrCollapsedEntries.add(key);
|
|
662
|
+
}
|
|
663
|
+
else {
|
|
664
|
+
this.expandedOrCollapsedEntries.delete(key);
|
|
665
|
+
}
|
|
666
|
+
return this;
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Expand by position string
|
|
670
|
+
*/
|
|
671
|
+
expandPos(posStr) {
|
|
672
|
+
const entry = this.getEntryAtPos(posStr);
|
|
673
|
+
if (entry) {
|
|
674
|
+
this.expand(entry.origin, entry.docId);
|
|
675
|
+
}
|
|
676
|
+
return this;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Collapse by position string
|
|
680
|
+
*/
|
|
681
|
+
collapsePos(posStr) {
|
|
682
|
+
const entry = this.getEntryAtPos(posStr);
|
|
683
|
+
if (entry) {
|
|
684
|
+
this.collapse(entry.origin, entry.docId);
|
|
685
|
+
}
|
|
686
|
+
return this;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Expand by position array
|
|
690
|
+
*
|
|
691
|
+
* @param pos Position array e.g. [1, 2, 3]
|
|
692
|
+
*/
|
|
693
|
+
expandPosArray(pos) {
|
|
694
|
+
const entry = this.getPosArray(pos);
|
|
695
|
+
if (entry) {
|
|
696
|
+
this.expand(entry.origin, entry.docId);
|
|
697
|
+
}
|
|
698
|
+
return this;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Collapse by position array
|
|
702
|
+
*
|
|
703
|
+
* @param pos Position array e.g. [1, 2, 3]
|
|
704
|
+
*/
|
|
705
|
+
collapsePosArray(pos) {
|
|
706
|
+
const entry = this.getPosArray(pos);
|
|
707
|
+
if (entry) {
|
|
708
|
+
this.collapse(entry.origin, entry.docId);
|
|
709
|
+
}
|
|
710
|
+
return this;
|
|
711
|
+
}
|
|
712
|
+
getEntryAtPos(posStr) {
|
|
713
|
+
// Save current position
|
|
714
|
+
const savedStack = [...this.currentEntryStack];
|
|
715
|
+
const found = this.gotoPos(posStr);
|
|
716
|
+
const entry = found ? this.getCurrentEntry() : null;
|
|
717
|
+
// Restore position
|
|
718
|
+
this.currentEntryStack = savedStack;
|
|
719
|
+
return entry;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Collapse all entries
|
|
723
|
+
*/
|
|
724
|
+
collapseAll() {
|
|
725
|
+
this.expandedOrCollapsedEntries.clear();
|
|
726
|
+
this.expandAllByDefault = false;
|
|
727
|
+
return this;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Expand all entries
|
|
731
|
+
*/
|
|
732
|
+
expandAll() {
|
|
733
|
+
this.expandedOrCollapsedEntries.clear();
|
|
734
|
+
this.expandAllByDefault = true;
|
|
735
|
+
return this;
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Expand entries up to a specific level
|
|
739
|
+
*/
|
|
740
|
+
expandToLevel(level) {
|
|
741
|
+
this.expandLevel = level;
|
|
742
|
+
return this;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Check if an entry is expanded
|
|
746
|
+
*/
|
|
747
|
+
isExpanded(entry) {
|
|
748
|
+
// Root is always expanded
|
|
749
|
+
if (entry.isRoot()) {
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
752
|
+
// Check level-based expansion
|
|
753
|
+
if (this.expandLevel > 0 && entry.getLevel() <= this.expandLevel) {
|
|
754
|
+
return true;
|
|
755
|
+
}
|
|
756
|
+
return this.isExpandedByDocId(entry.origin, entry.docId);
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Check if an entry is expanded by origin and docId
|
|
760
|
+
* Does not check expandLevel - only checks the expand/collapse state
|
|
761
|
+
*
|
|
762
|
+
* @param origin Origin of the entry
|
|
763
|
+
* @param docId Document ID of the entry
|
|
764
|
+
* @returns true if expanded
|
|
765
|
+
*/
|
|
766
|
+
isExpandedByDocId(origin, docId) {
|
|
767
|
+
const key = (0, types_1.scopedDocIdKey)((0, types_1.createScopedDocId)(origin, docId));
|
|
768
|
+
// Check if this is the root
|
|
769
|
+
const root = this.view.getRoot();
|
|
770
|
+
if (root.docId === docId && root.origin === origin) {
|
|
771
|
+
return true;
|
|
772
|
+
}
|
|
773
|
+
if (this.expandAllByDefault) {
|
|
774
|
+
return !this.expandedOrCollapsedEntries.has(key);
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
return this.expandedOrCollapsedEntries.has(key);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
isExpandAllByDefault() {
|
|
781
|
+
return this.expandAllByDefault;
|
|
782
|
+
}
|
|
783
|
+
isCollapseAllByDefault() {
|
|
784
|
+
return !this.expandAllByDefault;
|
|
785
|
+
}
|
|
786
|
+
getExpandLevel() {
|
|
787
|
+
return this.expandLevel;
|
|
788
|
+
}
|
|
789
|
+
// ===== State Getters/Setters =====
|
|
790
|
+
getSelectedOrDeselectedEntries() {
|
|
791
|
+
return new Set(this.selectedOrDeselectedEntries);
|
|
792
|
+
}
|
|
793
|
+
setSelectedOrDeselectedEntries(entries) {
|
|
794
|
+
this.selectedOrDeselectedEntries = new Set(entries);
|
|
795
|
+
return this;
|
|
796
|
+
}
|
|
797
|
+
getExpandedOrCollapsedEntries() {
|
|
798
|
+
return new Set(this.expandedOrCollapsedEntries);
|
|
799
|
+
}
|
|
800
|
+
setExpandedOrCollapsedEntries(entries) {
|
|
801
|
+
this.expandedOrCollapsedEntries = new Set(entries);
|
|
802
|
+
return this;
|
|
803
|
+
}
|
|
804
|
+
// ===== Child Entry Methods =====
|
|
805
|
+
/**
|
|
806
|
+
* Get child documents of an entry
|
|
807
|
+
*/
|
|
808
|
+
childDocuments(entry, descending = false) {
|
|
809
|
+
const docs = entry.getChildDocuments();
|
|
810
|
+
const filtered = docs.filter(e => this.isVisible(e));
|
|
811
|
+
return descending ? filtered.reverse() : filtered;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Get child categories of an entry
|
|
815
|
+
*/
|
|
816
|
+
childCategories(entry, descending = false) {
|
|
817
|
+
const cats = entry.getChildCategories();
|
|
818
|
+
const filtered = cats.filter(e => this.isVisible(e));
|
|
819
|
+
return descending ? filtered.reverse() : filtered;
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Get all child entries of an entry
|
|
823
|
+
*/
|
|
824
|
+
childEntries(entry, descending = false) {
|
|
825
|
+
const entries = entry.getChildEntries();
|
|
826
|
+
const filtered = entries.filter(e => this.isVisible(e));
|
|
827
|
+
return descending ? filtered.reverse() : filtered;
|
|
828
|
+
}
|
|
829
|
+
// ===== Range/Key-based Child Queries =====
|
|
830
|
+
/**
|
|
831
|
+
* Get child documents within a key range (inclusive)
|
|
832
|
+
*
|
|
833
|
+
* @param entry Parent entry
|
|
834
|
+
* @param startKey Start key value
|
|
835
|
+
* @param endKey End key value
|
|
836
|
+
* @param descending Whether to return in descending order
|
|
837
|
+
* @returns Filtered child documents within the range
|
|
838
|
+
*/
|
|
839
|
+
childDocumentsBetween(entry, startKey, endKey, descending = false) {
|
|
840
|
+
const docs = entry.getChildDocuments();
|
|
841
|
+
const filtered = docs.filter(e => {
|
|
842
|
+
if (!this.isVisible(e))
|
|
843
|
+
return false;
|
|
844
|
+
const sortKey = e.getSortKey();
|
|
845
|
+
const firstValue = sortKey.values.length > 0 ? sortKey.values[0] : null;
|
|
846
|
+
// Check if value is within range
|
|
847
|
+
const afterStart = (0, types_1.compareValues)(firstValue, startKey, false) >= 0;
|
|
848
|
+
const beforeEnd = (0, types_1.compareValues)(firstValue, endKey, false) <= 0;
|
|
849
|
+
return afterStart && beforeEnd;
|
|
850
|
+
});
|
|
851
|
+
return descending ? filtered.reverse() : filtered;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Get child documents by key (exact or prefix match)
|
|
855
|
+
*
|
|
856
|
+
* @param entry Parent entry
|
|
857
|
+
* @param key Key value to search for
|
|
858
|
+
* @param isExact Whether to match exactly or by prefix
|
|
859
|
+
* @param descending Whether to return in descending order
|
|
860
|
+
* @returns Matching child documents
|
|
861
|
+
*/
|
|
862
|
+
childDocumentsByKey(entry, key, isExact, descending = false) {
|
|
863
|
+
if (isExact) {
|
|
864
|
+
return this.childDocumentsBetween(entry, key, key, descending);
|
|
865
|
+
}
|
|
866
|
+
// Prefix match - use key to key + max char
|
|
867
|
+
const endKey = key + String.fromCharCode(0xFFFF);
|
|
868
|
+
return this.childDocumentsBetween(entry, key, endKey, descending);
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Get child categories within a key range (inclusive)
|
|
872
|
+
*
|
|
873
|
+
* @param entry Parent entry
|
|
874
|
+
* @param startKey Start key value
|
|
875
|
+
* @param endKey End key value
|
|
876
|
+
* @param descending Whether to return in descending order
|
|
877
|
+
* @returns Filtered child categories within the range
|
|
878
|
+
*/
|
|
879
|
+
childCategoriesBetween(entry, startKey, endKey, descending = false) {
|
|
880
|
+
const cats = entry.getChildCategories();
|
|
881
|
+
const filtered = cats.filter(e => {
|
|
882
|
+
if (!this.isVisible(e))
|
|
883
|
+
return false;
|
|
884
|
+
const catValue = e.getCategoryValue();
|
|
885
|
+
// Check if value is within range
|
|
886
|
+
const afterStart = (0, types_1.compareValues)(catValue, startKey, false) >= 0;
|
|
887
|
+
const beforeEnd = (0, types_1.compareValues)(catValue, endKey, false) <= 0;
|
|
888
|
+
return afterStart && beforeEnd;
|
|
889
|
+
});
|
|
890
|
+
return descending ? filtered.reverse() : filtered;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Get child categories by key (exact or prefix match)
|
|
894
|
+
*
|
|
895
|
+
* @param entry Parent entry
|
|
896
|
+
* @param key Key value to search for
|
|
897
|
+
* @param isExact Whether to match exactly or by prefix
|
|
898
|
+
* @param descending Whether to return in descending order
|
|
899
|
+
* @returns Matching child categories
|
|
900
|
+
*/
|
|
901
|
+
childCategoriesByKey(entry, key, isExact, descending = false) {
|
|
902
|
+
if (isExact) {
|
|
903
|
+
return this.childCategoriesBetween(entry, key, key, descending);
|
|
904
|
+
}
|
|
905
|
+
// Prefix match - use key to key + max char
|
|
906
|
+
const endKey = key + String.fromCharCode(0xFFFF);
|
|
907
|
+
return this.childCategoriesBetween(entry, key, endKey, descending);
|
|
908
|
+
}
|
|
909
|
+
// ===== Sorted Entry Lookup =====
|
|
910
|
+
/**
|
|
911
|
+
* Compare two position arrays for sorting
|
|
912
|
+
*/
|
|
913
|
+
static comparePositions(pos1, pos2) {
|
|
914
|
+
const len = Math.min(pos1.length, pos2.length);
|
|
915
|
+
for (let i = 0; i < len; i++) {
|
|
916
|
+
if (pos1[i] !== pos2[i]) {
|
|
917
|
+
return pos1[i] - pos2[i];
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
return pos1.length - pos2.length;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Get all occurrences of a document in the view, sorted by position
|
|
924
|
+
*
|
|
925
|
+
* @param origin Origin of the document
|
|
926
|
+
* @param docId Document ID
|
|
927
|
+
* @returns Array of entries sorted by position
|
|
928
|
+
*/
|
|
929
|
+
getSortedEntries(origin, docId) {
|
|
930
|
+
const entries = this.view.getEntries(origin, docId);
|
|
931
|
+
return entries
|
|
932
|
+
.filter(e => this.isVisible(e))
|
|
933
|
+
.sort((a, b) => VirtualViewNavigator.comparePositions(a.getPosition(), b.getPosition()));
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Get all occurrences of multiple documents in the view, sorted by position
|
|
937
|
+
*
|
|
938
|
+
* @param origin Origin of the documents
|
|
939
|
+
* @param docIds Set of document IDs
|
|
940
|
+
* @returns Array of entries sorted by position
|
|
941
|
+
*/
|
|
942
|
+
getSortedEntriesMultiple(origin, docIds) {
|
|
943
|
+
const allEntries = [];
|
|
944
|
+
for (const docId of docIds) {
|
|
945
|
+
const entries = this.view.getEntries(origin, docId);
|
|
946
|
+
allEntries.push(...entries);
|
|
947
|
+
}
|
|
948
|
+
return allEntries
|
|
949
|
+
.filter(e => this.isVisible(e))
|
|
950
|
+
.sort((a, b) => VirtualViewNavigator.comparePositions(a.getPosition(), b.getPosition()));
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Get all occurrences of scoped document IDs in the view, sorted by position
|
|
954
|
+
*
|
|
955
|
+
* @param scopedDocIds Set of scoped document IDs (origin + docId)
|
|
956
|
+
* @returns Array of entries sorted by position
|
|
957
|
+
*/
|
|
958
|
+
getSortedEntriesScoped(scopedDocIds) {
|
|
959
|
+
const allEntries = [];
|
|
960
|
+
for (const scopedId of scopedDocIds) {
|
|
961
|
+
const entries = this.view.getEntries(scopedId.origin, scopedId.docId);
|
|
962
|
+
allEntries.push(...entries);
|
|
963
|
+
}
|
|
964
|
+
return allEntries
|
|
965
|
+
.filter(e => this.isVisible(e))
|
|
966
|
+
.sort((a, b) => VirtualViewNavigator.comparePositions(a.getPosition(), b.getPosition()));
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Get document IDs sorted by their position in the view
|
|
970
|
+
*
|
|
971
|
+
* @param origin Origin of the documents
|
|
972
|
+
* @param docIds Set of document IDs
|
|
973
|
+
* @returns Array of document IDs sorted by their position in the view
|
|
974
|
+
*/
|
|
975
|
+
getSortedDocIds(origin, docIds) {
|
|
976
|
+
const sortedEntries = this.getSortedEntriesMultiple(origin, docIds);
|
|
977
|
+
// Use a Set to track seen docIds and maintain order
|
|
978
|
+
const seen = new Set();
|
|
979
|
+
const result = [];
|
|
980
|
+
for (const entry of sortedEntries) {
|
|
981
|
+
if (!seen.has(entry.docId)) {
|
|
982
|
+
seen.add(entry.docId);
|
|
983
|
+
result.push(entry.docId);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
return result;
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Get scoped document IDs sorted by their position in the view
|
|
990
|
+
*
|
|
991
|
+
* @param scopedDocIds Set of scoped document IDs
|
|
992
|
+
* @returns Array of scoped document IDs sorted by their position in the view
|
|
993
|
+
*/
|
|
994
|
+
getSortedDocIdsScoped(scopedDocIds) {
|
|
995
|
+
const sortedEntries = this.getSortedEntriesScoped(scopedDocIds);
|
|
996
|
+
// Use a Set to track seen docIds and maintain order
|
|
997
|
+
const seen = new Set();
|
|
998
|
+
const result = [];
|
|
999
|
+
for (const entry of sortedEntries) {
|
|
1000
|
+
const key = (0, types_1.scopedDocIdKey)({ origin: entry.origin, docId: entry.docId });
|
|
1001
|
+
if (!seen.has(key)) {
|
|
1002
|
+
seen.add(key);
|
|
1003
|
+
result.push({ origin: entry.origin, docId: entry.docId });
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
return result;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
exports.VirtualViewNavigator = VirtualViewNavigator;
|
|
1010
|
+
//# sourceMappingURL=VirtualViewNavigator.js.map
|