UNPKG

aspen-tree-model

Version:
184 lines 8.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TreeStateManager = exports.Operation = void 0; const aspen_core_1 = require("aspen-core"); const notificar_1 = require("notificar"); const types_1 = require("./types"); var Operation; (function (Operation) { Operation[Operation["SetExpanded"] = 1] = "SetExpanded"; Operation[Operation["SetCollapsed"] = 2] = "SetCollapsed"; Operation[Operation["SetActive"] = 3] = "SetActive"; })(Operation = exports.Operation || (exports.Operation = {})); var StashKeyFrameFlag; (function (StashKeyFrameFlag) { StashKeyFrameFlag[StashKeyFrameFlag["Expanded"] = 1] = "Expanded"; StashKeyFrameFlag[StashKeyFrameFlag["Collapsed"] = 2] = "Collapsed"; StashKeyFrameFlag[StashKeyFrameFlag["Disabled"] = 4] = "Disabled"; })(StashKeyFrameFlag || (StashKeyFrameFlag = {})); class TreeStateManager { constructor(root) { this.events = new notificar_1.Notificar(); this.expandedDirectories = new Map(); this._scrollOffset = 0; this.stashing = false; this.stashLockingItems = new Set(); this.handleExpansionChange = (target, isExpanded, isVisibleAtSurface) => { if (this.stashing) { this.stashKeyframes.set(target.id, isExpanded ? StashKeyFrameFlag.Expanded : StashKeyFrameFlag.Collapsed); } if (this.stashKeyframes && !this.stashing) { // If something was "manually" (through user interaction) expanded *after* recording ended, we must remove its parents from undo queue if (isExpanded) { let p = target; while (p) { if (this.stashKeyframes.has(p.id)) { let flags = this.stashKeyframes.get(p.id); flags |= StashKeyFrameFlag.Disabled; this.stashKeyframes.set(p.id, flags); } p = p.parent; } this.stashLockingItems.add(target); } if (this.stashLockingItems && this.stashLockingItems.has(target) && !isExpanded) { let p = target; while (p) { if (this.stashKeyframes.has(p.id)) { let flags = this.stashKeyframes.get(p.id); flags &= ~StashKeyFrameFlag.Disabled; this.stashKeyframes.set(p.id, flags); } p = p.parent; } this.stashLockingItems.delete(target); } } let relativePath = this.expandedDirectories.get(target); if (isExpanded && !relativePath) { relativePath = this.root.pathfx.relative(this.root.path, target.path); this.expandedDirectories.set(target, relativePath); this.events.dispatch(types_1.TreeStateEvent.DidChangeDirExpansionState, relativePath, isExpanded, isVisibleAtSurface); } else if (!isExpanded && relativePath) { this.expandedDirectories.delete(target); this.events.dispatch(types_1.TreeStateEvent.DidChangeDirExpansionState, relativePath, isExpanded, isVisibleAtSurface); } }; this.handleDidChangePath = (target) => { if (this.expandedDirectories.has(target)) { const prevPath = this.expandedDirectories.get(target); const newPath = this.root.pathfx.relative(this.root.path, target.path); this.expandedDirectories.set(target, newPath); this.events.dispatch(types_1.TreeStateEvent.DidChangeRelativePath, prevPath, newPath); } }; this.root = root; this.root.onDidChangeDirExpansionState(this.handleExpansionChange); this.root.onDidChangePath(this.handleDidChangePath); } get scrollOffset() { return this._scrollOffset; } saveScrollOffset(scrollOffset) { this._scrollOffset = scrollOffset; this.events.dispatch(types_1.TreeStateEvent.DidChangeScrollOffset, scrollOffset); } onDidLoadState(callback) { return this.events.add(types_1.TreeStateEvent.DidLoadState, callback); } onChangeScrollOffset(callback) { return this.events.add(types_1.TreeStateEvent.DidChangeScrollOffset, callback); } onDidChangeDirExpansionState(callback) { return this.events.add(types_1.TreeStateEvent.DidChangeDirExpansionState, callback); } onDidChangeRelativePath(callback) { return this.events.add(types_1.TreeStateEvent.DidChangeRelativePath, callback); } /** * Starts recording directory expands and collapses * * `reverseStash` can then be used to undo all those actions. * * Internally used by `FileTree#peekABoo` * * Stashing can be used for peeking file(s) temporarily, where you don't want a mess of expanded folders for user to deal with. * * `beginStashing` => then expand the folder(s) you need to get to the file you want => `endStahsing` => once you're done => `reverseStash` to clean up the mess */ beginStashing() { this.stashing = true; this.stashKeyframes = new Map(); } /** * Ends the recording session of directory expands and collapses * * See documentation for `beginStashing` for details */ endStashing() { this.stashing = false; this.stashLockingItems.clear(); } /** * Reverses all the recorded directory expands and collapses * * See documentation for `beginStashing` for details */ async reverseStash() { if (!this.stashKeyframes) { return; } this.endStashing(); const keyframes = Array.from(this.stashKeyframes); this.stashKeyframes = null; for (const [targetID, flags] of keyframes) { const frameDisabled = (flags & StashKeyFrameFlag.Disabled) === StashKeyFrameFlag.Disabled; const target = aspen_core_1.FileEntry.getFileEntryById(targetID); // Check if target is still available (not disposed) if (!target || frameDisabled) { continue; } if ((flags & StashKeyFrameFlag.Expanded) === StashKeyFrameFlag.Expanded) { this.root.collapseDirectory(target); } else if ((flags & StashKeyFrameFlag.Collapsed) === StashKeyFrameFlag.Collapsed) { await this.root.expandDirectory(target); } } } async loadTreeState(state) { if (state) { for (const relDirPath of state.expandedDirectories.buried) { try { const dirH = await this.root.forceLoadFileEntryAtPath(relDirPath); if (dirH && dirH.constructor === aspen_core_1.Directory) { await this.root.expandDirectory(dirH, false); } } catch (error) { } } for (const relDirPath of state.expandedDirectories.atSurface) { try { const dirH = await this.root.forceLoadFileEntryAtPath(relDirPath); if (dirH && dirH.constructor === aspen_core_1.Directory) { await this.root.expandDirectory(dirH, true); } } catch (error) { } } this._scrollOffset = typeof state.scrollPosition === 'number' && state.scrollPosition > -1 ? state.scrollPosition : this._scrollOffset; this.events.dispatch(types_1.TreeStateEvent.DidLoadState); } } /** * This will ensure directory expansions aren't altered atleast for directories leading to file to be excluded when `reverseStash` is called */ excludeFromStash(file) { if (this.stashKeyframes && !this.stashing) { this.handleExpansionChange(file.constructor === aspen_core_1.FileEntry ? file.parent : file, true, this.root.isItemVisibleAtSurface(file)); } } } exports.TreeStateManager = TreeStateManager; //# sourceMappingURL=TreeStateManager.js.map