PageSourceSearch

https://id.priyadi.net/assets/controllers/file-manager/tree_controller-XtTEtaU.js

js priyadi.net collected 2026-10-02 06:18:20 UTC 160,163 bytes, 3,332 lines download raw bytes

1function _array_like_to_array(arr, len) {
2    if (len == null || len > arr.length) len = arr.length;
3    for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4    return arr2;
5}
6function _array_without_holes(arr) {
7    if (Array.isArray(arr)) return _array_like_to_array(arr);
8}
9function _assert_this_initialized(self) {
10    if (self === void 0) {
11        throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
12    }
13    return self;
14}
15function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
16    try {
17        var info = gen[key](arg);
18        var value = info.value;
19    } catch (error) {
20        reject(error);
21        return;
22    }
23    if (info.done) {
24        resolve(value);
25    } else {
26        Promise.resolve(value).then(_next, _throw);
27    }
28}
29function _async_to_generator(fn) {
30    return function() {
31        var self = this, args = arguments;
32        return new Promise(function(resolve, reject) {
33            var gen = fn.apply(self, args);
34            function _next(value) {
35                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
36            }
37            function _throw(err) {
38                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
39            }
40            _next(undefined);
41        });
42    };
43}
44function _class_call_check(instance, Constructor) {
45    if (!(instance instanceof Constructor)) {
46        throw new TypeError("Cannot call a class as a function");
47    }
48}
49function _defineProperties(target, props) {
50    for(var i = 0; i < props.length; i++){
51        var descriptor = props[i];
52        descriptor.enumerable = descriptor.enumerable || false;
53        descriptor.configurable = true;
54        if ("value" in descriptor) descriptor.writable = true;
55        Object.defineProperty(target, descriptor.key, descriptor);
56    }
57}
58function _create_class(Constructor, protoProps, staticProps) {
59    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
60    if (staticProps) _defineProperties(Constructor, staticProps);
61    return Constructor;
62}
63function _define_property(obj, key, value) {
64    if (key in obj) {
65        Object.defineProperty(obj, key, {
66            value: value,
67            enumerable: true,
68            configurable: true,
69            writable: true
70        });
71    } else {
72        obj[key] = value;
73    }
74    return obj;
75}
76function _get_prototype_of(o) {
77    _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
78        return o.__proto__ || Object.getPrototypeOf(o);
79    };
80    return _get_prototype_of(o);
81}
82function _inherits(subClass, superClass) {
83    if (typeof superClass !== "function" && superClass !== null) {
84        throw new TypeError("Super expression must either be null or a function");
85    }
86    subClass.prototype = Object.create(superClass && superClass.prototype, {
87        constructor: {
88            value: subClass,
89            writable: true,
90            configurable: true
91        }
92    });
93    if (superClass) _set_prototype_of(subClass, superClass);
94}
95function _instanceof(left, right) {
96    if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
97        return !!right[Symbol.hasInstance](left);
98    } else {
99        return left instanceof right;
100    }
101}
102function _iterable_to_array(iter) {
103    if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
104}
105function _non_iterable_spread() {
106    throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
107}
108function _possible_constructor_return(self, call) {
109    if (call && (_type_of(call) === "object" || typeof call === "function")) {
110        return call;
111    }
112    return _assert_this_initialized(self);
113}
114function _set_prototype_of(o, p) {
115    _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
116        o.__proto__ = p;
117        return o;
118    };
119    return _set_prototype_of(o, p);
120}
121function _to_consumable_array(arr) {
122    return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
123}
124function _type_of(obj) {
125    "@swc/helpers - typeof";
126    return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
127}
128function _unsupported_iterable_to_array(o, minLen) {
129    if (!o) return;
130    if (typeof o === "string") return _array_like_to_array(o, minLen);
131    var n = Object.prototype.toString.call(o).slice(8, -1);
132    if (n === "Object" && o.constructor) n = o.constructor.name;
133    if (n === "Map" || n === "Set") return Array.from(n);
134    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
135}
136function _is_native_reflect_construct() {
137    if (typeof Reflect === "undefined" || !Reflect.construct) return false;
138    if (Reflect.construct.sham) return false;
139    if (typeof Proxy === "function") return true;
140    try {
141        Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
142        return true;
143    } catch (e) {
144        return false;
145    }
146}
147function _create_super(Derived) {
148    var hasNativeReflectConstruct = _is_native_reflect_construct();
149    return function _createSuperInternal() {
150        var Super = _get_prototype_of(Derived), result;
151        if (hasNativeReflectConstruct) {
152            var NewTarget = _get_prototype_of(this).constructor;
153            result = Reflect.construct(Super, arguments, NewTarget);
154        } else {
155            result = Super.apply(this, arguments);
156        }
157        return _possible_constructor_return(this, result);
158    };
159}
160function _ts_generator(thisArg, body) {
161    var f, y, t, g, _ = {
162        label: 0,
163        sent: function() {
164            if (t[0] & 1) throw t[1];
165            return t[1];
166        },
167        trys: [],
168        ops: []
169    };
170    return(g = {
171        next: verb(0),
172        "throw": verb(1),
173        "return": verb(2)
174    }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
175        return this;
176    }), g);
177    function verb(n) {
178        return function(v) {
179            return step([
180                n,
181                v
182            ]);
183        };
184    }
185    function step(op) {
186        if (f) throw new TypeError("Generator is already executing.");
187        while(_)try {
188            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
189            if (y = 0, t) op = [
190                op[0] & 2,
191                t.value
192            ];
193            switch(op[0]){
194                case 0:
195                case 1:
196                    t = op;
197                    break;
198                case 4:
199                    _.label++;
200                    return {
201                        value: op[1],
202                        done: false
203                    };
204                case 5:
205                    _.label++;
206                    y = op[1];
207                    op = [
208                        0
209                    ];
210                    continue;
211                case 7:
212                    op = _.ops.pop();
213                    _.trys.pop();
214                    continue;
215                default:
216                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
217                        _ = 0;
218                        continue;
219                    }
220                    if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
221                        _.label = op[1];
222                        break;
223                    }
224                    if (op[0] === 6 && _.label < t[1]) {
225                        _.label = t[1];
226                        t = op;
227                        break;
228                    }
229                    if (t && _.label < t[2]) {
230                        _.label = t[2];
231                        _.ops.push(op);
232                        break;
233                    }
234                    if (t[2]) _.ops.pop();
235                    _.trys.pop();
236                    continue;
237            }
238            op = body.call(thisArg, _);
239        } catch (e) {
240            op = [
241                6,
242                e
243            ];
244            y = 0;
245        } finally{
246            f = t = 0;
247        }
248        if (op[0] & 5) throw op[1];
249        return {
250            value: op[0] ? op[1] : void 0,
251            done: true
252        };
253    }
254}
255import { Controller } from "@hotwired/stimulus";
256import { DirectoryNode, FileSystemNode } from "../../lib/file-manager/models/FileSystemNode.js";
257import { FileSystemService } from "../../lib/file-manager/services/FileSystemService.js";
258import { positionContextMenu, escapeHtml, getParentPath, setupInPlaceRename, decodeNodePath } from "../../lib/file-manager/utils/index.js";
259import { loadSvgIntoElement } from "../../lib/file-manager/utils/svg-loader.js";
260import { getActionAvailability } from "../../lib/file-manager/models/ActionAvailability.js";
261/**
262 * Name a new folder is pre-filled with, matching the browser pane
263 */ var NEW_FOLDER_NAME = "New Folder";
264var TreeController = /*#__PURE__*/ function(Controller) {
265    "use strict";
266    _inherits(TreeController, Controller);
267    var _super = _create_super(TreeController);
268    function TreeController() {
269        _class_call_check(this, TreeController);
270        var _this;
271        _this = _super.apply(this, arguments);
272        _define_property(_assert_this_initialized(_this), "service", void 0);
273        _define_property(_assert_this_initialized(_this), "contextMenuPath", null);
274        _define_property(_assert_this_initialized(_this), "rootNode", null);
275        _define_property(_assert_this_initialized(_this), "nodeMap", new Map()) // O(1) path-to-node lookup
276        ;
277        _define_property(_assert_this_initialized(_this), "selectedPath", null) // null = no selection, '' = root selected
278        ;
279        _define_property(_assert_this_initialized(_this), "isTrashSelected", false) // Whether the trash node is currently selected
280        ;
281        _define_property(_assert_this_initialized(_this), "subdirectoryEventUnsubscribe", null);
282        _define_property(_assert_this_initialized(_this), "isRenamingInPlace", false);
283        _define_property(_assert_this_initialized(_this), "renameInputElement", null);
284        _define_property(_assert_this_initialized(_this), "renderPending", false);
285        // Clipboard state for copy/cut operations
286        _define_property(_assert_this_initialized(_this), "clipboardPaths", []);
287        _define_property(_assert_this_initialized(_this), "clipboardIdentifiers", []) // Store identifiers for cross-directory paste
288        ;
289        _define_property(_assert_this_initialized(_this), "clipboardMode", null);
290        // ==================== Drag & Drop from Browser Pane ====================
291        // Drag state for tree items
292        _define_property(_assert_this_initialized(_this), "isDragging", false);
293        _define_property(_assert_this_initialized(_this), "draggedPath", null);
294        return _this;
295    }
296    _create_class(TreeController, [
297        {
298            key: "connect",
299            value: function connect() {
300                var _this = this;
301                this.service = new FileSystemService({
302                    rootIdentifier: this.rootIdentifierValue
303                });
304                // Close context menu when clicking elsewhere
305                document.addEventListener("click", this.handleDocumentClick.bind(this));
306                // Subscribe to subdirectory detection events to update toggle visibility
307                this.subdirectoryEventUnsubscribe = this.service.on("directory:hasSubdirectory", function(event) {
308                    // A directory now knows it has subdirectories, update the item controller
309                    _this.updateItemCanExpand(event.identifier, true);
310                });
311                // Load initial directory using the root identifier
312                // Skip if skipAutoLoad is true (manager will control initial load)
313                if (!this.skipAutoLoadValue) {
314                    this.loadRootDirectory();
315                }
316            }
317        },
318        {
319            key: "disconnect",
320            value: function disconnect() {
321                this.service.cancelAll();
322                document.removeEventListener("click", this.handleDocumentClick.bind(this));
323                // Unsubscribe from events
324                if (this.subdirectoryEventUnsubscribe) {
325                    this.subdirectoryEventUnsubscribe();
326                    this.subdirectoryEventUnsubscribe = null;
327                }
328            }
329        },
330        {
331            key: "handleDocumentClick",
332            value: /**
333     * Handle document click to close context menu
334     */ function handleDocumentClick() {
335                this.hideContextMenu();
336            }
337        },
338        {
339            key: "loadRootDirectory",
340            value: /**
341     * Load the root directory and render the tree
342     */ function loadRootDirectory() {
343                var _this = this;
344                return _async_to_generator(function() {
345                    var error;
346                    return _ts_generator(this, function(_state) {
347                        switch(_state.label){
348                            case 0:
349                                _this.showLoading();
350                                _this.hideError();
351                                _state.label = 1;
352                            case 1:
353                                _state.trys.push([
354                                    1,
355                                    3,
356                                    ,
357                                    4
358                                ]);
359                                return [
360                                    4,
361                                    _this.service.loadDirectory(_this.rootIdentifierValue)
362                                ];
363                            case 2:
364                                _this.rootNode = _state.sent();
365                                _this.rootNode.isExpanded = true;
366                                _this.nodeMap.clear();
367                                _this.registerNode(_this.rootNode);
368                                _this.render();
369                                _this.hideLoading();
370                                return [
371                                    3,
372                                    4
373                                ];
374                            case 3:
375                                error = _state.sent();
376                                // Ignore AbortError - it just means a newer request superseded this one
377                                if (_instanceof(error, Error) && error.name === "AbortError") {
378                                    return [
379                                        2
380                                    ];
381                                }
382                                _this.hideLoading();
383                                _this.showError(error);
384                                return [
385                                    3,
386                                    4
387                                ];
388                            case 4:
389                                return [
390                                    2
391                                ];
392                        }
393                    });
394                })();
395            }
396        },
397        {
398            /**
399     * Initialize the tree with an existing directory node (no fetch required).
400     * Used when the browser has already loaded the directory data.
401     * 
402     * If the directory has ancestors (i.e., it's not the root), this method
403     * builds a tree structure from the root ancestor down to the current directory,
404     * expanding all ancestors so the user can navigate up to parent directories.
405     * After the initial render, it asynchronously loads sibling directories for
406     * each ancestor so the full tree structure is visible.
407     */ key: "initializeWithDirectory",
408            value: function initializeWithDirectory(directory) {
409                this.hideLoading();
410                this.hideError();
411                this.nodeMap.clear();
412                // Get the ancestor chain from root to parent
413                var ancestors = directory.ancestors;
414                if (ancestors.length === 0) {
415                    // Directory is at root level - use it directly as the root
416                    this.rootNode = directory;
417                    this.rootNode.isExpanded = true;
418                    this.selectedPath = directory.path;
419                    this.registerNode(this.rootNode);
420                } else {
421                    // Build tree structure from ancestors
422                    // ancestors[0] is the root, ancestors[last] is the immediate parent
423                    this.rootNode = ancestors[0];
424                    this.rootNode.isExpanded = true;
425                    // Link ancestors together via children arrays
426                    for(var i = 0; i < ancestors.length - 1; i++){
427                        var parent = ancestors[i];
428                        var child = ancestors[i + 1];
429                        parent.children = [
430                            child
431                        ];
432                        parent.isExpanded = true;
433                        parent.hasSubdirectory = true;
434                    }
435                    // Link the last ancestor (immediate parent) to the current directory
436                    var immediateParent = ancestors[ancestors.length - 1];
437                    immediateParent.children = [
438                        directory
439                    ];
440                    immediateParent.isExpanded = true;
441                    immediateParent.hasSubdirectory = true;
442                    // Expand the current directory and mark it as selected
443                    directory.isExpanded = true;
444                    this.selectedPath = directory.path;
445                    // Register all nodes starting from root
446                    this.registerNode(this.rootNode);
447                }
448                this.render();
449                // After initial render, load siblings for expanded ancestors
450                if (ancestors.length > 0) {
451                    this.loadAncestorSiblings(ancestors);
452                }
453            }
454        },
455        {
456            key: "loadAncestorSiblings",
457            value: /**
458     * Load sibling directories for each ancestor in the chain.
459     * Called after initializeWithDirectory to populate the tree with siblings
460     * that aren't in the direct ancestor path. Loads all ancestors in parallel.
461     */ function loadAncestorSiblings(ancestors) {
462                var _this = this;
463                return _async_to_generator(function() {
464                    var loadPromises;
465                    return _ts_generator(this, function(_state) {
466                        switch(_state.label){
467                            case 0:
468                                if (ancestors.length === 0) return [
469                                    2
470                                ];
471                                loadPromises = ancestors.map(function() {
472                                    var _ref = _async_to_generator(function(ancestor) {
473                                        var loaded, existingByPath, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, child, mergedChildren, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, loadedChild, existing, subdirs, error;
474                                        return _ts_generator(this, function(_state) {
475                                            switch(_state.label){
476                                                case 0:
477                                                    _state.trys.push([
478                                                        0,
479                                                        2,
480                                                        ,
481                                                        3
482                                                    ]);
483                                                    return [
484                                                        4,
485                                                        _this.service.loadDirectory(ancestor.id)
486                                                    ];
487                                                case 1:
488                                                    loaded = _state.sent();
489                                                    if (!loaded.children) return [
490                                                        2
491                                                    ];
492                                                    // Build a set of existing child paths to preserve expanded/selected state
493                                                    existingByPath = new Map();
494                                                    if (ancestor.children) {
495                                                        _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
496                                                        try {
497                                                            for(_iterator = ancestor.children[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
498                                                                child = _step.value;
499                                                                existingByPath.set(child.path, child);
500                                                            }
501                                                        } catch (err) {
502                                                            _didIteratorError = true;
503                                                            _iteratorError = err;
504                                                        } finally{
505                                                            try {
506                                                                if (!_iteratorNormalCompletion && _iterator.return != null) {
507                                                                    _iterator.return();
508                                                                }
509                                                            } finally{
510                                                                if (_didIteratorError) {
511                                                                    throw _iteratorError;
512                                                                }
513                                                            }
514                                                        }
515                                                    }
516                                                    // Merge: keep existing children (preserves expanded state), add new ones
517                                                    mergedChildren = [];
518                                                    _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
519                                                    try {
520                                                        for(_iterator1 = loaded.children[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
521                                                            loadedChild 
521= _step1.value;
522                                                            existing = existingByPath.get(loadedChild.path);
523                                                            if (existing) {
524                                                                mergedChildren.push(existing);
525                                                            } else {
526                                                                mergedChildren.push(loadedChild);
527                                                                if (loadedChild.isDirectory()) {
528                                                                    _this.registerNode(loadedChild);
529                                                                }
530                                                            }
531                                                        }
532                                                    } catch (err) {
533                                                        _didIteratorError1 = true;
534                                                        _iteratorError1 = err;
535                                                    } finally{
536                                                        try {
537                                                            if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
538                                                                _iterator1.return();
539                                                            }
540                                                        } finally{
541                                                            if (_didIteratorError1) {
542                                                                throw _iteratorError1;
543                                                            }
544                                                        }
545                                                    }
546                                                    ancestor.children = mergedChildren;
547                                                    subdirs = ancestor.getSubdirectories();
548                                                    ancestor.hasSubdirectory = subdirs.length > 0;
549                                                    return [
550                                                        3,
551                                                        3
552                                                    ];
553                                                case 2:
554                                                    error = _state.sent();
555                                                    // Silently ignore - the skeleton tree is still usable
556                                                    if (_instanceof(error, Error) && error.name === "AbortError") return [
557                                                        2
558                                                    ];
559                                                    console.warn("Failed to load siblings for ancestor:", ancestor.path, error);
560                                                    return [
561                                                        3,
562                                                        3
563                                                    ];
564                                                case 3:
565                                                    return [
566                                                        2
567                                                    ];
568                                            }
569                                        });
570                                    });
571                                    return function(ancestor) {
572                                        return _ref.apply(this, arguments);
573                                    };
574                                }());
575                                return [
576                                    4,
577                                    Promise.all(loadPromises)
578                                ];
579                            case 1:
580                                _state.sent();
581                                _this.render();
582                                return [
583                                    2
584                                ];
585                        }
586                    });
587                })();
588            }
589        },
590        {
591            /**
592     * Sync the tree to show and select a directory that was loaded in the browser.
593     * This method integrates the directory and its ancestors into the existing tree
594     * without requiring a full re-render from root. It's designed to be called
595     * after browser navigation to keep the tree in sync.
596     * 
597     * @param directory The directory node loaded by the browser
598     */ key: "syncWithDirectory",
599            value: function syncWithDirectory(directory) {
600                // If we don't have a root node yet, initialize with this directory
601                if (!this.rootNode) {
602                    this.initializeWithDirectory(directory);
603                    return;
604                }
605                // Check if this directory is already in our tree
606                var existingNode = this.nodeMap.get(directory.path);
607                if (existingNode) {
608                    // Directory already exists in tree
609                    // Update children from the browser's loaded directory
610                    this.updateNodeChildren(existingNode, directory);
611                    // Expand to it and select it
612                    this.expandToPath(directory.path);
613                    this.setSelection(directory.path);
614                    this.render();
615                    return;
616                }
617                // Directory not in tree - we need to integrate it
618                // Walk up the ancestor chain to find where we connect to existing tree
619                var ancestors = directory.ancestors;
620                // Find the deepest ancestor that's already in our tree
621                var connectionPoint = null;
622                var connectionIndex = -1;
623                for(var i = ancestors.length - 1; i >= 0; i--){
624                    var ancestor = ancestors[i];
625                    var existing = this.nodeMap.get(ancestor.path);
626                    if (existing) {
627                        connectionPoint = existing;
628                        connectionIndex = i;
629                        break;
630                    }
631                }
632                if (connectionPoint) {
633                    var _this = this, _loop = function(i1) {
634                        var _parent_children;
635                        var childAncestor = ancestors[i1];
636                        // Check if this child is already in parent's children
637                        var existingChild = (_parent_children = parent.children) === null || _parent_children === void 0 ? void 0 : _parent_children.find(function(c) {
638                            return c.path === childAncestor.path;
639                        });
640                        if (existingChild && existingChild.isDirectory()) {
641                            // Use existing child node
642                            parent = existingChild;
643                            parent.isExpanded = true;
644                            parent.hasSubdirectory = true;
645                            _this.registerNode(parent);
646                        } else {
647                            // Need to add this ancestor as a child
648                            if (!parent.children) {
649                                parent.children = [];
650                            }
651                            parent.children.push(childAncestor);
652                            childAncestor.isExpanded = true;
653                            childAncestor.hasSubdirectory = true;
654                            _this.registerNode(childAncestor);
655                            parent = childAncestor;
656                        }
657                    };
658                    var _parent_children;
659                    // Found a connection point - build the chain from there
660                    var parent = connectionPoint;
661                    parent.isExpanded = true;
662                    parent.hasSubdirectory = true;
663                    // Add intermediate ancestors that weren't in the tree
664                    for(var i1 = connectionIndex + 1; i1 < ancestors.length; i1++)_loop(i1);
665                    // Now add the directory itself under the last ancestor
666                    var existingDir = (_parent_children = parent.children) === null || _parent_children === void 0 ? void 0 : _parent_children.find(function(c) {
667                        return c.path === directory.path;
668                    });
669                    if (!existingDir) {
670                        if (!parent.children) {
671                            parent.children = [];
672                        }
673                        parent.children.push(directory);
674                    } else if (existingDir.isDirectory()) {
675                        // Directory already exists - update its children from loaded data
676                        this.updateNodeChildren(existingDir, directory);
677                    }
678                    directory.isExpanded = true;
679                    // Update hasSubdirectory based on actual subdirectories
680                    var subdirs = directory.getSubdirectories();
681                    directory.hasSubdirectory = subdirs.length > 0;
682                    this.registerNode(directory);
683                    var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
684                    try {
685                        // Also register subdirectories so they can be found in nodeMap
686                        for(var _iterator = subdirs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
687                            var subdir = _step.value;
688                            this.registerNode(subdir);
689                        }
690                    } catch (err) {
691                        _didIteratorError = true;
692                        _iteratorError = err;
693                    } finally{
694                        try {
695                            if (!_iteratorNormalCompletion && _iterator.return != null) {
696                                _iterator.return();
697                            }
698                        } finally{
699                            if (_didIteratorError) {
700                                throw _iteratorError;
701                            }
702                        }
703                    }
704                } else {
705                    // No connection point found - this shouldn't happen if root is loaded,
706                    // but fall back to re-initializing with this directory
707                    this.initializeWithDirectory(directory);
708                    return;
709                }
710                // Update selection
711                this.selectedPath = directory.path;
712                // Re-render the tree to show the new structure
713                this.render();
714            }
715        },
716        {
717            key: "expandToPath",
718            value: /**
719     * Expand all ancestors to make a path visible in the tree.
720     * Does not select the path, just ensures it's visible.
721     */ function expandToPath(path) {
722                // Walk up the path and expand each parent
723                var parts = path.split("/");
724                var currentPath = "";
725                for(var i = 0; i < parts.length; i++){
726                    if (i > 0 || parts[0] !== "") {
727                        currentPath = currentPath ? currentPath + "/" + parts[i] : parts[i];
728                    }
729                    var node = this.nodeMap.get(currentPath);
730                    if (node && !node.isExpanded && node.canExpand) {
731                        node.isExpanded = true;
732                    }
733                }
734                // Also ensure root is expanded
735                if (this.rootNode) {
736                    this.rootNode.isExpanded = true;
737                }
738                this.render();
739            }
740        },
741        {
742            key: "updateNodeChildren",
743            value: /**
744     * Update a tree node's metadata from a browser-loaded directory.
745     * This syncs the tree's representation with the browser's loaded data.
746     * 
747     * IMPORTANT: This method must NOT modify existingNode.children because the
748     * existingNode may be shared with the browser controller. Modifying children
749     * to only contain directories would corrupt the browser's file listing.
750     * Instead, we only update metadata and register subdirectories in our nodeMap.
751     * The tree rendering uses getSubdirectories() to filter directories for display.
752     */ function updateNodeChildren(existingNode, loadedDirectory) {
753                // Get subdirectories from the loaded directory
754                var loadedSubdirs = loadedDirectory.getSubdirectories();
755                // Update hasSubdirectory based on whether there are subdirectories
756                existingNode.hasSubdirectory = loadedSubdirs.length > 0;
757                existingNode.isExpanded = true;
758                var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
759                try {
760                    // Register all subdirectories in our nodeMap so they can be found
761                    // We do NOT modify existingNode.children - it's shared with browser
762                    for(var _iterator = loadedSubdirs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
763                        var subdir = _step.value;
764                        if (!this.nodeMap.has(subdir.path)) {
765                            this.registerNode(subdir);
766                        }
767                    }
768                } catch (err) {
769                    _didIteratorError = true;
770                    _iteratorError = err;
771                } finally{
772                    try {
773                        if (!_iteratorNormalCompletion && _iterator.return != null) {
774                            _iterator.return();
775                        }
776                    } finally{
777                        if (_didIteratorError) {
778                            throw _iteratorError;
779                        }
780                    }
781                }
782            }
783        },
784        {
785            key: "updateItemCanExpand",
786            value: /**
787     * Update a specific item when its node's canExpand changes
788     */ function updateItemCanExpand(path, _canExpand) {
789                var itemElement = this.findItemElement(path);
790                if (itemElement) {
791                    var controller = this.application.getControllerForElementAndIdentifier(itemElement, "file-manager--tree-item");
792                    if (controller === null || controller === void 0 ? void 0 : controller.rerender) {
793                        controller.rerender();
794                    }
795                }
796            }
797        },
798        {
799            key: "findItemElement",
800            value: /**
801     * Find an item element by path
802     */ function findItemElement(path) {
803                return this.treeTarget.querySelector('[data-file-manager--tree-item-path-value="'.concat(CSS.escape(path), '"]'));
804            }
805        },
806        {
807            key: "handleItemToggle",
808            value: /**
809     * Handle item toggle event from tree-item controller
810     */ function handleItemToggle(event) {
811                var _this = this;
812                return _async_to_generator(function() {
813                    var path;
814                    return _ts_generator(this, function(_state) {
815                        switch(_state.label){
816                            case 0:
817                                path = event.detail.path;
818                                return [
819                                    4,
820                                    _this.toggleDirectory(path)
821                                ];
822                            case 1:
823                                _state.sent();
824                                return [
825                                    2
826                                ];
827                        }
828                    });
829                })();
830            }
831        },
832        {
833            /**
834     * Handle item select event from tree-item controller
835     */ key: "handleItemSelect",
836            value: function handleItemSelect(event) {
837                var path = event.detail.path;
838                this.selectDirectory(path);
839            }
840        },
841        {
842            key: "handleItemDblSelect",
843            value: /**
844     * Handle item double-select event from tree-item controller
845     */ function handleItemDblSelect(event) {
846                var _this = this;
847                return _async_to_generator(function() {
848                    var path;
849                    return _ts_generator(this, function(_state) {
850                        switch(_state.label){
851                            case 0:
852                                path = event.detail.path;
853                                return [
854                                    4,
855                                    _this.handleDoubleClick(path)
856                                ];
857                            case 1:
858                                _state.sent();
859                                return [
860                                    2
861                                ];
862                        }
863                    });
864                })();
865            }
866        },
867        {
868            /**
869     * Handle item context menu event from tree-item controller
870     */ key: "handleItemContextMenu",
871            value: function handleItemContextMenu(event) {
872                var _event_detail = event.detail, path = _event_detail.path, x = _event_detail.x, y = _event_detail.y;
873                this.selectedPath = path;
874                this.contextMenuPath = path;
875                this.updateSelectedItem();
876                this.showContextMenu(x, y);
877            }
878        },
879        {
880            /**
881     * Handle keyboard shortcuts on the tree pane
882     */ key: "handleKeydown",
883            value: function handleKeydown(event) {
884                // Don't handle keyboard shortcuts while in-place editing
885                if (this.isRenamingInPlace) return;
886                // Enter: Toggle expand/collapse of selected directory
887                if (event.key === "Enter") {
888                    event.preventDefault();
889                    // selectedPath can be '' for root, so check if we have any selection
890                    // by verifying a directory was actually selected (not the initial state)
891                    if (this.selectedPath !== null) {
892                        this.handleDoubleClick(this.selectedPath);
893                    }
894                    return;
895                }
896                // Delete: Move selected directory to trash (Shift+Delete: permanent delete)
897                if (event.key === "Delete") {
898                    event.preventDefault();
899                    if (this.selectedPath !== null && this.selectedPath !== "") {
900                        this.deleteDirectory(this.selectedPath, event.shiftKey);
901                    }
902                    return;
903                }
904                // F2: Rename selected directory
905                if (event.key === "F2") {
906                    event.preventDefault();
907                    if (this.selectedPath !== null && this.selectedPath !== "") {
908                        this.startInPlaceRename(this.selectedPath);
909                    }
910                    return;
911                }
912                // Ctrl+C: Copy selected directory
913                if ((event.ctrlKey || event.metaKey) && event.key === "c") {
914                    event.preventDefault();
915                    if (this.selectedPath !== null && this.selectedPath !== "") {
916                        this.copyDirectory(this.selectedPath);
917                    }
918                    return;
919                }
920                // Ctrl+X: Cut selected directory
921                if ((event.ctrlKey || event.metaKey) && event.key === "x") {
922                    event.preventDefault();
923                    if (this.selectedPath !== null && this.selectedPath !== "") {
924                        this.cutDirectory(this.selectedPath);
925                    }
926                    return;
927                }
928                // Ctrl+V: Paste into selected directory
929                if ((event.ctrlKey || event.metaKey) && event.key === "v") {
930                    event.preventDefault();
931                    var _this_selectedPath;
932                    var targetPath = (_this_selectedPath = this.selectedPath) !== null && _this_selectedPath !== void 0 ? _this_selectedPath : "";
933                    this.pasteIntoDirectory(targetPath);
934                    return;
935                }
936            }
937        },
938        {
939            key: "toggleDirectory",
940            value: /**
941     * Toggle a directory's expanded state
942     */ function toggleDirectory(path) {
943                var _this = this;
944                return _async_to_generator(function() {
945                    var node, itemElement, controller, _controller_rerender, _controller_rerender1, loadedNode, error, _controller_rerender2, _controller_rerender3;
946                    return _ts_generator(this, function(_state) {
947                        switch(_state.label){
948                            case 0:
949                                node = _this.findNodeByPath(path);
950                                if (!node || !node.isDirectory()) return [
951                                    2
952                                ];
953                                if (!node.canExpand) return [
954                                    2
955                                ];
956                                itemElement = _this.findItemElement(path);
957                                controller = itemElement ? _this.application.getControllerForElementAndIdentifier(itemElement, "file-manager--tree-item") : null;
958                                if (!node.isExpanded) return [
959                                    3,
960                                    1
961                                ];
962                                // Collapse
963                                node.isExpanded = false;
964                                controller === null || controller === void 0 ? void 0 : (_controller_rerender = controller.rerender) === null || _controller_rerender === void 0 ? void 0 : _controller_rerender.call(controller);
965                                _this.removeChildrenFromDOM(path);
966                                return [
967                                    3,
968                                    7
969                                ];
970                            case 1:
971                                if (!!node.hasLoadedChildren) return [
972                                    3,
973                                    6
974                                ];
975                                node.isLoading = true;
976                                controller === null || controller === void 0 ? void 0 : (_controller_rerender1 = controller.rerender) === null || _controller_rerender1 === void 0 ? void 0 : _controller_rerender1.call(controller);
977                                _state.label = 2;
978                            case 2:
979                                _state.trys.push([
980                                    2,
981                                    4,
982                                    5,
983                                    6
984                                ]);
985                                return [
986                                    4,
987                                    _this.service.loadDirectory(node.id)
988                                ];
989                            case 3:
990                                loadedNode = _state.sent();
991                                node.children = loadedNode.children;
992                                // Register newly loaded children in nodeMap
993                                _this.registerNode(node);
994                                return [
995                                    3,
996                                    6
997                                ];
998                            case 4:
999                                error = _state.sent();
1000                                console.error("Failed to load directory:", error);
1001                                return [
1002                                    3,
1003                                    6
1004                                ];
1005                            case 5:
1006                                node.isLoading = false;
1007                                controller === null || controller === void 0 ? void 0 : (_controller_rerender2 = controller.rerender) === null || _controller_rerender2 === void 0 ? void 0 : _controller_rerender2.call(controller);
1008                                return [
1009                                    7
1010                                ];
1011                            case 6:
1012                                // After loading, only expand if there are subdirectories
1013                                if (node.canExpand && node.getSubdirectories().length > 0) {
1014                                    ;
1015                                    node.isExpanded = true;
1016                                    controller === null || controller === void 0 ? void 0 : (_controller_rerender3 = controller.rerender) === null || _controller_rerender3 === void 0 ? void 0 : _controller_rerender3.call(controller);
1017                                    _this.appendChildrenToDOM(node, itemElement);
1018                                }
1019                                _state.label = 7;
1020                            case 7:
1021                                return [
1022                                    2
1023                                ];
1024                        }
1025                    });
1026                })();
1027            }
1028        },
1029        {
1030            /**
1031     * Select a directory (single click) - also dispatches navigation event
1032     */ key: "selectDirectory",
1033            value: function selectDirectory(path) {
1034                var previousPath = this.selectedPath;
1035                this.selectedPath = path;
1036                // Update previous and current selection
1037                if (previousPath !== path) {
1038                    this.updateItemSelected(previousPath, false);
1039                }
1040                this.updateItemSelected(path, true);
1041                // Find the node to get its identifier
1042                var node = this.findNodeByPath(path);
1043                var identifier = (node === null || node === void 0 ? void 0 : node.id) || (path === "" ? this.rootIdentifierValue : undefined);
1044                // Dispatch select event to navigate browser pane
1045                this.dispatch("select", {
1046                    detail: {
1047                        path: path,
1048                        identifier: identifier
1049                    },
1050                    bubbles: true
1051                });
1052            }
1053        },
1054        {
1055            /**
1056     * Set selection visually without dispatching navigation event.
1057     * Used when the browser has already navigated and we just need to sync the tree UI.
1058     */ key: "setSelection",
1059            value: function setSelection(path) {
1060                var previousPath = this.selectedPath;
1061                this.selectedPath = path;
1062                // Deselect trash when a regular directory is selected
1063                if (this.isTrashSelected) {
1064                    this.isTrashSelected = false;
1065                    // Re-render to update trash item visual state
1066                    var trashItem = this.treeTarget.querySelector(".file-tree__item--trash .file-tree__item-content");
1067                    if (trashItem) {
1068                        trashItem.classList.remove("file-tree__item-content--selected");
1069                    }
1070                }
1071                // Update previous and current selection visually
1072                if (previousPath !== path) {
1073                    this.updateItemSelected(previousPath, false);
1074                }
1075                this.updateItemSelected(path, true);
1076            }
1077        },
1078        {
1079            key: "updateItemSelected",
1080            value: /**
1081     * Update a specific item's selected value
1082     */ function updateItemSelected(path, selected) {
1083                if (path === null) return;
1084                var itemElement = this.findItemElement(path);
1085                if (itemElement) {
1086                    var controller = this.application.getControllerForElementAndIdentifier(itemElement, "file-manager--tree-item");
1087                    if (controller) {
1088                        controller.selectedValue = selected;
1089                    }
1090                }
1091            }
1092        },
1093        {
1094            key: "updateSelectedItem",
1095            value: /**
1096     * Update selected item (for context menu)
1097     */ function updateSelectedItem() {
1098                var _this = this;
1099                // Clear all selections and set the new one
1100                var allItems = this.treeTarget.querySelectorAll('[data-controller="file-manager--tree-item"]');
1101                allItems.forEach(function(el) {
1102                    var controller = _this.application.getControllerForElementAndIdentifier(el, "file-manager--tree-item");
1103                    if (controller) {
1104                        controller.selectedValue = false;
1105                    }
1106                });
1107                if (this.selectedPath !== null) {
1108                    this.updateItemSelected(this.selectedPath, true);
1109                }
1110            }
1111        },
1112        {
1113            key: "handleDoubleClick",
1114            value: /**
1115     * Handle double click - toggle expand/collapse AND navigate
1116     */ function handleDoubleClick(path) {
1117                var _this = this;
1118                return _async_to_generator(function() {
1119                    var node;
1120                    return _ts_generator(this, function(_state) {
1121                        switch(_state.label){
1122                            case 0:
1123                                _this.selectedPath = path;
1124                                _this.updateSelectedItem();
1125                                node = _this.findNodeByPath(path);
1126                                if (!node || !node.isDirectory()) return [
1127                                    2
1128                                ];
1129                                if (!node.canExpand) return [
1130                                    3,
1131                                    2
1132                                ];
1133                                return [
1134                                    4,
1135                                    _this.toggleDirectory(path)
1136                                ];
1137                            case 1:
1138                                _state.sent();
1139                                _state.label = 2;
1140                            case 2:
1141                                // Also navigate browser pane
1142                                _this.dispatch("select", {
1143                                    detail: {
1144                                        path: path,
1145                                        identifier: node.id
1146                                    },
1147                                    bubbles: true
1148                                });
1149                                return [
1150                                    2
1151                                ];
1152                        }
1153                    });
1154                })();
1155            }
1156        },
1157        {
1158            /**
1159     * Get a node by its path. Used by tree-item controllers to access their node data.
1160     */ key: "getNode",
1161            value: function getNode(path) {
1162                var _this_nodeMap_get;
1163                return (_this_nodeMap_get = this.nodeMap.get(path)) !== null && _this_nodeMap_get !== void 0 ? _this_nodeMap_get : null;
1164            }
1165        },
1166        {
1167            key: "findNodeByPath",
1168            value: /**
1169     * Find a node by its path in the tree (uses nodeMap for O(1) lookup)
1170     */ function findNodeByPath(path) {
1171                var _this_nodeMap_get;
1172                return (_this_nodeMap_get = this.nodeMap.get(path)) !== null && _this_nodeMap_get !== void 0 ? _this_nodeMap_get : null;
1173            }
1174        },
1175        {
1176            key: "registerNode",
1177            value: /**
1178     * Register a node in the nodeMap (and all its children recursively)
1179     */ function registerNode(node) {
1180                this.nodeMap.set(node.path, node);
1181                if (node.children) {
1182                    var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1183                    try {
1184                        for(var _iterator = node.children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1185                            var child = _step.value;
1186                            if (child.isDirectory()) {
1187                                this.registerNode(child);
1188                            }
1189                        }
1190                    } catch (err) {
1191                        _didIteratorError = true;
1192                        _iteratorError = err;
1193                    } finally{
1194                        try {
1195                            if (!_iteratorNormalCompletion && _iterator.return != null) {
1196                                _iterator.return();
1197                            }
1198                        } finally{
1199                            if (_didIteratorError) {
1200                                throw _iteratorError;
1201                            }
1202                        }
1203                    }
1204                }
1205            }
1206        },
1207        {
1208            key: "unregisterNode",
1209            value: /**
1210     * Unregister a node from the nodeMap (and all its children recursively)
1211     */ function unregisterNode(node) {
1212                this.nodeMap.delete(node.path);
1213                if (node.children) {
1214                    var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1215                    try {
1216                        for(var _iterator = node.children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1217                            var child = _step.value;
1218                            if (child.isDirectory()) {
1219                                this.unregisterNode(child);
1220                            }
1221                        }
1222                    } catch (err) {
1223                        _didIteratorError = true;
1224                        _iteratorError = err;
1225                    } finally{
1226                        try {
1227                            if (!_iteratorNormalCompletion && _iterator.return != null) {
1228                                _iterator.return();
1229                            }
1230                        } finally{
1231                            if (_didIteratorError) {
1232                                throw _iteratorError;
1233                            }
1234                        }
1235                    }
1236                }
1237            }
1238        },
1239        {
1240            key: "render",
1241            value: /**
1242     * Render the tree (full re-render)
1243     *
1244     * A re-render rebuilds every row, which would throw away the in-place
1245     * input the user is typing a name into - and those renders arrive
1246     * unbidden, from the browser pane syncing a directory it has just
1247     * finished loading. Hold them until the input is done instead.
1248     */ function render() {
1249                if (this.isRenamingInPlace) {
1250                    this.renderPending = true;
1251                    return;
1252                }
1253                this.renderPending = false;
1254                if (!this.rootNode) {
1255                    this.treeTarget.innerHTML = "";
1256                    return;
1257                }
1258                var html = this.renderDirectoryItem(this.rootNode, 0);
1259                // Add trash node at the bottom of the tree
1260                if (this.trashRootIdentifierValue) {
1261                    html += this.renderTrashItem();
1262                }
1263                this.treeTarget.innerHTML = html;
1264                // Load SVG icons for trash item
1265                if (this.trashRootIdentifierValue) {
1266                    this.loadSvgPlaceholders(this.treeTarget);
1267                }
1268            }
1269        },
1270        {
1271            key: "flushPendingRender",
1272            value: /**
1273     * Run a re-render that was held back while an in-place input was open
1274     */ function flushPendingRender() {
1275                if (this.renderPending) {
1276                    this.render();
1277                }
1278            }
1279        },
1280        {
1281            key: "renderDirectoryItem",
1282            value: /**
1283     * Render a directory item as an li element with optional children ul
1284     */ function renderDirectoryItem(node, depth) {
1285                var isSelected = node.path === this.selectedPath;
1286                var html = '\n            <li class="file-tree__item"\n                draggable="true"\n                data-controller="file-manager--tree-item"\n                data-file-manager--tree-item-path-value="'.concat(escapeHtml(node.path), '"\n                data-file-manager--tree-item-depth-value="').concat(depth, '"\n                data-file-manager--tree-item-selected-value="').concat(isSelected, '"\n                data-action="contextmenu->file-manager--tree-item#contextMenu dragstart->file-manager--tree#handleItemDragStart dragend->file-manager--tree#handleItemDragEnd dragover->file-manager--tree#handleItemDragOver dragleave->file-manager--tree#handleItemDragLeave drop->file-manager--tree#handleItemDrop">\n        ');
1287                // Render children if expanded
1288                if (node.isExpanded && node.children) {
1289                    var subdirectories = node.getSubdirectories().sort(function(a, b) {
1290                        return a.name.localeCompare(b.name);
1291                    });
1292                    if (subdirectories.length > 0) {
1293                        html += '<ul class="file-tree__children">';
1294                        var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1295                        try {
1296                            for(var _iterator = subdirectories[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1297                                var child = _step.value;
1298                                html += this.renderDirectoryItem(child, depth + 1);
1299                            }
1300                        } catch (err) {
1301                            _didIteratorError = true;
1302                            _iteratorError = err;
1303                        } finally{
1304                            try {
1305                                if (!_iteratorNormalCompletion && _iterator.return != null) {
1306                                    _iterator.return();
1307                                }
1308                            } finally{
1309                                if (_didIteratorError) {
1310                                    throw _iteratorError;
1311                                }
1312                            }
1313                        }
1314                        html += "</ul>";
1315                    }
1316                }
1317                html += "</li>";
1318                return html;
1319            }
1320        },
1321        {
1322            key: "renderTrashItem",
1323            value: /**
1324     * Render the trash item as a special non-expandable tree entry
1325     */ function renderTrashItem() {
1326                var isSelected = this.isTrashSelected;
1327                return '\n            <li class="file-tree__item file-tree__item--trash"\n                data-action="contextmenu->file-manager--tree#handleTrashContextMenu">\n                <div class="file-tree__item-content'.concat(isSelected ? " file-tree__item-content--selected" : "", '" style="padding-left: 0px">\n                    <span class="file-tree__toggle file-tree__toggle--disabled">\n                        <span class="file-tree__toggle-placeholder"></span>\n                    </span>\n                    <a href="#" class="file-tree__link"\n                       data-action="click->file-manager--tree#handleTrashClick">\n                        <span class="context-menu__svg-icon file-tree__folder-icon" data-svg-url="').concat(escapeHtml(this.iconTrashXValue), '" aria-hidden="true"></span>\n                        <span class="file-tree__name">').concat(escapeHtml(this.transTrashValue), "</span>\n                    </a>\n                </div>\n            </li>\n        ");
1328            }
1329        },
1330        {
1331            key: "appendChildrenToDOM",
1332            value: /**
1333     * Append children to DOM without full re-render
1334     */ function appendChildrenToDOM(node, itemElement) {
1335                if (!itemElement) return;
1336                var subdirectories = node.getSubdirectories().sort(function(a, b) {
1337                    return a.name.localeCompare(b.name);
1338                });
1339                if (subdirectories.length === 0) return;
1340                var childrenUl = this.getOrCreateChildrenList(itemElement);
1341                // Get depth from current item
1342                // Note: Double-dash in attribute name creates hyphenated dataset property
1343                var currentDepth = parseInt(itemElement.getAttribute("data-file-manager--tree-item-depth-value") || "0", 10);
1344                // Render children
1345                var childrenHtml = "";
1346                var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1347                try {
1348                    for(var _iterator = subdirectories[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1349                        var child = _step.value;
1350                        childrenHtml += this.renderDirectoryItem(child, currentDepth + 1);
1351                    }
1352                } catch (err) {
1353                    _didIteratorError = true;
1354                    _iteratorError = err;
1355                } finally{
1356                    try {
1357                        if (!_iteratorNormalCompletion && _iterator.return != null) {
1358                            _iterator.return();
1359                        }
1360                    } finally{
1361                        if (_didIteratorError) {
1362                            throw _iteratorError;
1363                        }
1364                    }
1365                }
1366                childrenUl.innerHTML = childrenHtml;
1367            }
1368        },
1369        {
1370            key: "removeChildrenFromDOM",
1371            value: /**
1372     * Remove children from DOM without full re-render
1373     */ function removeChildrenFromDOM(path) {
1374                var itemElement = this.findItemElement(path);
1375                if (!itemElement) return;
1376                var childrenUl = itemElement.querySelector(":scope > .file-tree__children");
1377                if (childrenUl) {
1378                    childrenUl.remove();
1379                }
1380            }
1381        },
1382        {
1383            key: "showLoading",
1384            value: /**
1385     * Show loading indicator
1386     */ function showLoading() {
1387                if (this.hasLoadingTarget) {
1388                    this.loadingTarget.classList.remove("hidden");
1389                    this.treeTarget.classList.add("hidden");
1390                }
1391            }
1392        },
1393        {
1394            key: "hideLoading",
1395            value: /**
1396     * Hide loading indicator
1397     */ function hideLoading() {
1398                if (this.hasLoadingTarget) {
1399                    this.loadingTarget.classList.add("hidden");
1400                    this.treeTarget.classList.remove("hidden");
1401                }
1402            }
1403        },
1404        {
1405            key: "showError",
1406            value: /**
1407     * Show error message
1408     */ function showError(error) {
1409                if (this.hasErrorTarget) {
1410                    var message = this.transErrorValue.replace("%message%", error.message);
1411                    this.errorTarget.textContent = message;
1412                    this.errorTarget.classList.remove("hidden");
1413                    this.treeTarget.classList.add("hidden");
1414                }
1415            }
1416        },
1417        {
1418            key: "hideError",
1419            value: /**
1420     * Hide error message
1421     */ function hideError() {
1422                if (this.hasErrorTarget) {
1423                    this.errorTarget.classList.add("hidden");
1424                    this.treeTarget.classList.remove("hidden");
1425                }
1426            }
1427        },
1428        {
1429            key: "navigateTo",
1430            value: /**
1431     * Programmatically select and navigate to a path by identifier.
1432     * Ensures root is loaded first if needed, then expands ancestors and selects the target.
1433     */ function navigateTo(identifier) {
1434                var _this = this;
1435                return _async_to_generator(function() {
1436                    var node, ancestors, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, ancestor, cachedAncestor, err, error;
1437                    return _ts_generator(this, function(_state) {
1438                        switch(_state.label){
1439                            case 0:
1440                                _state.trys.push([
1441                                    0,
1442                                    13,
1443                                    ,
1444                                    14
1445                                ]);
1446                                if (!!_this.rootNode) return [
1447                                    3,
1448                                    2
1449                                ];
1450                                return [
1451                                    4,
1452                                    _this.loadRootDirectory()
1453                                ];
1454                            case 1:
1455                                _state.sent();
1456                                _state.label = 2;
1457                            case 2:
1458                                // If we're navigating to root, just select it
1459                                if (identifier === _this.rootIdentifierValue) {
1460                                    _this.selectedPath = "";
1461                                    _this.render();
1462                                    return [
1463                                        2
1464                                    ];
1465                                }
1466                                return [
1467                                    4,
1468                                    _this.service.getNode(identifier)
1469                                ];
1470                            case 3:
1471                                node = _state.sent();
1472                                if (!node || !node.isDirectory()) return [
1473                                    2
1474                                ];
1475                                // Expand all ancestor directories
1476                                ancestors = node.ancestors;
1477                                _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1478                                _state.label = 4;
1479                            case 4:
1480                                _state.trys.push([
1481                                    4,
1482                                    10,
1483                                    11,
1484                                    12
1485                                ]);
1486                                _iterator = ancestors[Symbol.iterator]();
1487                                _state.label = 5;
1488                            case 5:
1489                                if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
1490                                    3,
1491                                    9
1492                                ];
1493                                ancestor = _step.value;
1494                                // Find the matching node in our 
1494cache and expand it
1495                                cachedAncestor = _this.service.getCached(ancestor.id);
1496                                if (!(cachedAncestor && cachedAncestor.isDirectory())) return [
1497                                    3,
1498                                    8
1499                                ];
1500                                if (!!cachedAncestor.hasLoadedChildren) return [
1501                                    3,
1502                                    7
1503                                ];
1504                                return [
1505                                    4,
1506                                    _this.service.loadDirectory(ancestor.id)
1507                                ];
1508                            case 6:
1509                                _state.sent();
1510                                // Register newly loaded children
1511                                _this.registerNode(cachedAncestor);
1512                                _state.label = 7;
1513                            case 7:
1514                                cachedAncestor.isExpanded = true;
1515                                _state.label = 8;
1516                            case 8:
1517                                _iteratorNormalCompletion = true;
1518                                return [
1519                                    3,
1520                                    5
1521                                ];
1522                            case 9:
1523                                return [
1524                                    3,
1525                                    12
1526                                ];
1527                            case 10:
1528                                err = _state.sent();
1529                                _didIteratorError = true;
1530                                _iteratorError = err;
1531                                return [
1532                                    3,
1533                                    12
1534                                ];
1535                            case 11:
1536                                try {
1537                                    if (!_iteratorNormalCompletion && _iterator.return != null) {
1538                                        _iterator.return();
1539                                    }
1540                                } finally{
1541                                    if (_didIteratorError) {
1542                                        throw _iteratorError;
1543                                    }
1544                                }
1545                                return [
1546                                    7
1547                                ];
1548                            case 12:
1549                                // Also ensure the root is expanded
1550                                if (_this.rootNode) {
1551                                    _this.rootNode.isExpanded = true;
1552                                }
1553                                _this.selectedPath = node.path;
1554                                _this.render();
1555                                return [
1556                                    3,
1557                                    14
1558                                ];
1559                            case 13:
1560                                error = _state.sent();
1561                                console.error("Failed to navigate to path:", error);
1562                                return [
1563                                    3,
1564                                    14
1565                                ];
1566                            case 14:
1567                                return [
1568                                    2
1569                                ];
1570                        }
1571                    });
1572                })();
1573            }
1574        },
1575        {
1576            key: "refresh",
1577            value: /**
1578     * Refresh the tree from the root
1579     */ function refresh() {
1580                var _this = this;
1581                return _async_to_generator(function() {
1582                    return _ts_generator(this, function(_state) {
1583                        switch(_state.label){
1584                            case 0:
1585                                _this.service.clearCache();
1586                                return [
1587                                    4,
1588                                    _this.loadRootDirectory()
1589                                ];
1590                            case 1:
1591                                _state.sent();
1592                                return [
1593                                    2
1594                                ];
1595                        }
1596                    });
1597                })();
1598            }
1599        },
1600        {
1601            /**
1602     * Get the FileSystemService instance (for external access)
1603     */ key: "getService",
1604            value: function getService() {
1605                return this.service;
1606            }
1607        },
1608        {
1609            /**
1610     * Get the currently selected path
1611     * Returns null if no selection, '' for root, or the path string
1612     */ key: "getSelectedPath",
1613            value: function getSelectedPath() {
1614                return this.selectedPath;
1615            }
1616        },
1617        {
1618            /**
1619     * Clear the current selection
1620     */ key: "clearSelection",
1621            value: function clearSelection() {
1622                if (this.selectedPath === null) return;
1623                // Remove highlight from previously selected item
1624                var previousSelected = this.element.querySelector(".file-tree__item--selected");
1625                if (previousSelected) {
1626                    previousSelected.classList.remove("file-tree__item--selected");
1627                }
1628                this.selectedPath = null;
1629                this.dispatchSelectionChange();
1630            }
1631        },
1632        {
1633            // ==================== Context Menu ====================
1634            /**
1635     * Handle context menu on empty area of tree
1636     */ key: "treeContextMenu",
1637            value: function treeContextMenu(event) {
1638                event.preventDefault();
1639                event.stopPropagation();
1640                // Only show if clicking on empty area (not on a tree item)
1641                var target = event.target;
1642                if (target.closest(".file-tree__item")) {
1643                    return;
1644                }
1645                // Use null to indicate no directory selected (empty area)
1646                this.contextMenuPath = null;
1647                this.showContextMenu(event.clientX, event.clientY);
1648            }
1649        },
1650        {
1651            key: "buildSelectionContext",
1652            value: /**
1653     * Build selection context for action availability calculation (tree pane)
1654     */ function buildSelectionContext() {
1655                var hasDirectorySelected = this.contextMenuPath !== null;
1656                var isRootSelected = this.contextMenuPath === "";
1657                return {
1658                    selectedCount: hasDirectorySelected ? 1 : 0,
1659                    isFileOnly: false,
1660                    isSingleSelection: hasDirectorySelected,
1661                    activePane: "tree",
1662                    isRootSelected: isRootSelected,
1663                    hasClipboard: this.hasClipboard()
1664                };
1665            }
1666        },
1667        {
1668            key: "showContextMenu",
1669            value: /**
1670     * Show context menu at specified position
1671     */ function showContextMenu(x, y) {
1672                if (!this.hasContextMenuTarget) return;
1673                // Use shared ActionAvailability for consistent behavior with toolbar
1674                var context = this.buildSelectionContext();
1675                var availability = getActionAvailability(context);
1676                var hasDirectorySelected = context.selectedCount > 0;
1677                var html = '<ul class="file-browser__context-menu-list">';
1678                // If a directory is selected (contextMenuPath is not null)
1679                if (hasDirectorySelected) {
1680                    // Open is always available when a directory is selected
1681                    if (availability.open) {
1682                        html += '\n                    <li class="file-browser__context-menu-item">\n                        <button type="button" data-action="click->file-manager--tree#contextMenuOpen">\n                            <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconPlayerPlayValue), '" aria-hidden="true"></span>\n                            ').concat(escapeHtml(this.transOpenValue), '\n                        </button>\n                    </li>\n                    <li class="file-browser__context-menu-separator"></li>\n                ');
1683                    }
1684                    // New Folder - creates inside the right-clicked directory
1685                    if (availability.newFolder) {
1686                        html += '\n                    <li class="file-browser__context-menu-item">\n                        <button type="button" data-action="click->file-manager--tree#contextMenuNewFolder">\n                            <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconFolderPlusValue), '" aria-hidden="true"></span>\n                            ').concat(escapeHtml(this.transNewFolderValue), '\n                        </button>\n                    </li>\n                    <li class="file-browser__context-menu-separator"></li>\n                ');
1687                    }
1688                    // Cut, Copy - only for non-root directories (based on availability)
1689                    if (availability.cut) {
1690                        html += '\n                    <li class="file-browser__context-menu-item">\n                        <button type="button" data-action="click->file-manager--tree#contextMenuCut">\n                            <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconCutValue), '" aria-hidden="true"></span>\n                            ').concat(escapeHtml(this.transCutValue), "\n                        </button>\n                    </li>\n                ");
1691                    }
1692                    if (availability.copy) {
1693                        html += '\n                    <li class="file-browser__context-menu-item">\n                        <button type="button" data-action="click->
1693file-manager--tree#contextMenuCopy">\n                            <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconCopyValue), '" aria-hidden="true"></span>\n                            ').concat(escapeHtml(this.transCopyValue), "\n                        </button>\n                    </li>\n                ");
1694                    }
1695                    // Paste - available when clipboard has items
1696                    html += '\n                <li class="file-browser__context-menu-item">\n                    <button type="button" data-action="click->file-manager--tree#contextMenuPaste"'.concat(availability.paste ? "" : " disabled", '>\n                        <span class="context-menu__svg-icon" data-svg-url="').concat(escapeHtml(this.iconClipboardCopyValue), '" aria-hidden="true"></span>\n                        ').concat(escapeHtml(this.transPasteValue), '\n                    </button>\n                </li>\n                <li class="file-browser__context-menu-separator"></li>\n            ');
1697                    // Rename, Delete - only for non-root directories (based on availability)
1698                    if (availability.rename) {
1699                        html += '\n                    <li class="file-browser__context-menu-item">\n                        <button type="button" data-action="click->file-manager--tree#contextMenuRename">\n                            <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconPencilValue), '" aria-hidden="true"></span>\n                            ').concat(escapeHtml(this.transRenameValue), "\n                        </button>\n                    </li>\n                ");
1700                    }
1701                    if (availability.delete) {
1702                        html += '\n                    <li class="file-browser__context-menu-item file-browser__context-menu-item--danger">\n                        <button type="button" data-action="click->file-manager--tree#contextMenuDelete">\n                            <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconTrashValue), '" aria-hidden="true"></span>\n                            ').concat(escapeHtml(this.transDeleteValue), '\n                        </button>\n                    </li>\n                    <li class="file-browser__context-menu-separator"></li>\n                ');
1703                    }
1704                } else {
1705                    // No directory selected (empty area) - New Folder and Paste act on
1706                    // the current selection, falling back to the root
1707                    if (availability.newFolder) {
1708                        html += '\n                    <li class="file-browser__context-menu-item">\n                        <button type="button" data-action="click->file-manager--tree#contextMenuNewFolder">\n                            <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconFolderPlusValue), '" aria-hidden="true"></span>\n                            ').concat(escapeHtml(this.transNewFolderValue), '\n                        </button>\n                    </li>\n                    <li class="file-browser__context-menu-separator"></li>\n                ');
1709                    }
1710                    html += '\n                <li class="file-browser__context-menu-item">\n                    <button type="button" data-action="click->file-manager--tree#contextMenuPaste"'.concat(availability.paste ? "" : " disabled", '>\n                        <span class="context-menu__svg-icon" data-svg-url="').concat(escapeHtml(this.iconClipboardCopyValue), '" aria-hidden="true"></span>\n                        ').concat(escapeHtml(this.transPasteValue), '\n                    </button>\n                </li>\n                <li class="file-browser__context-menu-separator"></li>\n            ');
1711                }
1712                // Refresh - always available
1713                html += '\n            <li class="file-browser__context-menu-item">\n                <button type="button" data-action="click->
1713file-manager--tree#contextMenuRefresh">\n                    <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconRefreshValue), '" aria-hidden="true"></span>\n                    ').concat(escapeHtml(this.transRefreshValue), "\n                </button>\n            </li>\n        ");
1714                html += "</ul>";
1715                this.contextMenuTarget.innerHTML = html;
1716                this.loadSvgPlaceholders(this.contextMenuTarget);
1717                positionContextMenu(this.contextMenuTarget, x, y);
1718            }
1719        },
1720        {
1721            key: "loadSvgPlaceholders",
1722            value: /**
1723     * Load SVG content into placeholder elements
1724     */ function loadSvgPlaceholders(container) {
1725                var placeholders = container.querySelectorAll("[data-svg-url]");
1726                placeholders.forEach(function(placeholder) {
1727                    var url = placeholder.dataset.svgUrl;
1728                    if (url) {
1729                        loadSvgIntoElement(placeholder, url);
1730                    }
1731                });
1732            }
1733        },
1734        {
1735            key: "hideContextMenu",
1736            value: /**
1737     * Hide context menu
1738     */ function hideContextMenu() {
1739                if (this.hasContextMenuTarget) {
1740                    this.contextMenuTarget.classList.add("hidden");
1741                }
1742            }
1743        },
1744        {
1745            /**
1746     * Context menu: Open
1747     */ key: "contextMenuOpen",
1748            value: function contextMenuOpen() {
1749                this.hideContextMenu();
1750                if (this.contextMenuPath === null) return;
1751                // Dispatch select event to open the directory
1752                this.dispatch("select", {
1753                    detail: {
1754                        path: this.contextMenuPath
1755                    },
1756                    bubbles: true
1757                });
1758            }
1759        },
1760        {
1761            /**
1762     * Context menu: Cut - store selected path for move operation
1763     */ key: "contextMenuCut",
1764            value: function contextMenuCut() {
1765                this.hideContextMenu();
1766                if (this.contextMenuPath === null || this.contextMenuPath === "") return;
1767                this.cutDirectory(this.contextMenuPath);
1768            }
1769        },
1770        {
1771            /**
1772     * Context menu: Copy - store selected path for copy operation
1773     */ key: "contextMenuCopy",
1774            value: function contextMenuCopy() {
1775                this.hideContextMenu();
1776                if (this.contextMenuPath === null || this.contextMenuPath === "") return;
1777                this.copyDirectory(this.contextMenuPath);
1778            }
1779        },
1780        {
1781            key: "contextMenuPaste",
1782            value: /**
1783     * Context menu: Paste - perform copy/move operation
1784     */ function contextMenuPaste() {
1785                var _this = this;
1786                return _async_to_generator(function() {
1787                    var _this_contextMenuPath, _ref, targetPath;
1788                    return _ts_generator(this, function(_state) {
1789                        switch(_state.label){
1790                            case 0:
1791                                _this.hideContextMenu();
1792                                // Paste into the selected directory, or root if no selection
1793                                targetPath = (_ref = (_this_contextMenuPath = _this.contextMenuPath) !== null && _this_contextMenuPath !== void 0 ? _this_contextMenuPath : _this.selectedPath) !== null && _ref !== void 0 ? _ref : "";
1794                                return [
1795                                    4,
1796                                    _this.pasteIntoDirectory(targetPath)
1797                                ];
1798                            case 1:
1799                                _state.sent();
1800                                return [
1801                                    2
1802                                ];
1803                        }
1804                    });
1805                })();
1806            }
1807        },
1808        {
1809            key: "contextMenuDelete",
1810            value: /**
1811     * Context menu: Delete - move selected directory to trash (or permanently if Shift is held)
1812     */ function contextMenuDelete(event) {
1813                var _this = this;
1814                return _async_to_generator(function() {
1815                    var permanent;
1816                    return _ts_generator(this, function(_state) {
1817                        switch(_state.label){
1818                            case 0:
1819                                permanent = _instanceof(event, MouseEvent) || _instanceof(event, KeyboardEvent) ? event.shiftKey : false;
1820                                _this.hideContextMenu();
1821                                if (_this.contextMenuPath === null || _this.contextMenuPath === "") return [
1822                                    2
1823                                ];
1824                                return [
1825                                    4,
1826                                    _this.deleteDirectory(_this.contextMenuPath, permanent)
1827                                ];
1828                            case 1:
1829                                _state.sent();
1830                                return [
1831                                    2
1832                                ];
1833                        }
1834                    });
1835                })();
1836            }
1837        },
1838        {
1839            // ==================== Clipboard Operations ====================
1840            /**
1841     * Cut a directory (store for move)
1842     */ key: "cutDirectory",
1843            value: function cutDirectory(path) {
1844                this.clipboardPaths = [
1845                    path
1846                ];
1847                // Store identifier at cut time so paste works across directories
1848                var node = this.findNodeByPath(path);
1849                this.clipboardIdentifiers = node ? [
1850                    node.id
1851                ] : [];
1852                this.clipboardMode = "cut";
1853                // Dispatch event to notify manager/browser
1854                this.dispatch("clipboardChange", {
1855                    detail: {
1856                        mode: "cut",
1857                        paths: this.clipboardPaths,
1858                        identifiers: this.clipboardIdentifiers,
1859                        hasClipboard: true
1860                    },
1861                    bubbles: true
1862                });
1863            }
1864        },
1865        {
1866            /**
1867     * Copy a directory (store for copy)
1868     */ key: "copyDirectory",
1869            value: function copyDirectory(path) {
1870                this.clipboardPaths = [
1871                    path
1872                ];
1873                // Store identifier at copy time so paste works across directories
1874                var node = this.findNodeByPath(path);
1875                this.clipboardIdentifiers = node ? [
1876                    node.id
1877                ] : [];
1878                this.clipboardMode = "copy";
1879                // Dispatch event to notify manager/browser
1880                this.dispatch("clipboardChange", {
1881                    detail: {
1882                        mode: "copy",
1883                        paths: this.clipboardPaths,
1884                        identifiers: this.clipboardIdentifiers,
1885                        hasClipboard: true
1886                    },
1887                    bubbles: true
1888                });
1889            }
1890        },
1891        {
1892            key: "pasteIntoDirectory",
1893            value: /**
1894     * Paste clipboard contents into target directory
1895     */ function pasteIntoDirectory(targetPath) {
1896                var _this = this;
1897                return _async_to_generator(function() {
1898                    var mode, targetNode, sourceIdentifiers, result, result1, error;
1899                    return _ts_generator(this, function(_state) {
1900                        switch(_state.label){
1901                            case 0:
1902                                if (!_this.hasClipboard()) return [
1903                                    2
1904                                ];
1905                                mode = _this.clipboardMode;
1906                                // Get target node to get its identifier
1907                                targetNode = _this.findNodeByPath(targetPath);
1908                                if (!targetNode) return [
1909                                    2
1910                                ];
1911                                // Use stored identifiers (captured at copy/cut time) for cross-directory paste
1912                                sourceIdentifiers = _this.clipboardIdentifiers;
1913                                if (sourceIdentifiers.length === 0) return [
1914                                    2
1915                                ];
1916                                _state.label = 1;
1917                            case 1:
1918                                _state.trys.push([
1919                                    1,
1920                                    8,
1921                                    ,
1922                                    9
1923                                ]);
1924                                if (!(mode === "copy")) return [
1925                                    3,
1926                                    4
1927                                ];
1928                                return [
1929                                    4,
1930                                    _this.service.copyMultiple(sourceIdentifiers, targetNode.id)
1931                                ];
1932                            case 2:
1933                                result = _state.sent();
1934                                return [
1935                                    4,
1936                                    _this.handlePasteResult(result, "copy", targetPath)
1937                                ];
1938                            case 3:
1939                                _state.sent();
1940                                return [
1941                                    3,
1942                                    7
1943                                ];
1944                            case 4:
1945                                if (!(mode === "cut")) return [
1946                                    3,
1947                                    7
1948                                ];
1949                                return [
1950                                    4,
1951                                    _this.service.moveMultiple(sourceIdentifiers, targetNode.id)
1952                                ];
1953                            case 5:
1954                                result1 = _state.sent();
1955                                return [
1956                                    4,
1957                                    _this.handlePasteResult(result1, "move", targetPath)
1958                                ];
1959                            case 6:
1960                                _state.sent();
1961                                // Clear clipboard after move
1962                                _this.clearClipboard();
1963                                _state.label = 7;
1964                            case 7:
1965                                return [
1966                                    3,
1967                                    9
1968                                ];
1969                            case 8:
1970                                error = _state.sent();
1971                                _this.dispatch("operationError", {
1972                                    detail: {
1973                                        type: mode === "copy" ? "copy" : "move",
1974                                        message: "Failed to ".concat(mode, " items"),
1975                                        error: error.message
1976                                    },
1977                                    bubbles: true
1978                                });
1979                                return [
1980                                    3,
1981                                    9
1982                                ];
1983                            case 9:
1984                                return [
1985                                    2
1986                                ];
1987                        }
1988                    });
1989                })();
1990            }
1991        },
1992        {
1993            key: "handlePasteResult",
1994            value: /**
1995     * Handle paste result and update tree
1996     */ function handlePasteResult(result, operation, targetPath) {
1997                var _this = this;
1998                return _async_to_generator(function() {
1999                    var successfulNodes, errors, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, r, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, node, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, r1, sourcePath;
2000                    return _ts_generator(this, function(_state) {
2001                        successfulNodes = [];
2002                        errors = [];
2003                        _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2004                        try {
2005                            for(_iterator = result.results[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2006                                r = _step.value;
2007                                if (r.success && r.node) {
2008                                    successfulNodes.push(r.node);
2009                                } else if (!r.success && r.error) {
2010                                    errors.push(r.error);
2011                                }
2012                            }
2013                        } catch (err) {
2014                            _didIteratorError = true;
2015                            _iteratorError = err;
2016                        } finally{
2017                            try {
2018                                if (!_iteratorNormalCompletion && _iterator.return != null) {
2019                                    _iterator.return();
2020                                }
2021                            } finally{
2022                                if (_didIteratorError) {
2023                                    throw _iteratorError;
2024                                }
2025                            }
2026                        }
2027                        _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2028                        try {
2029                            // Update tree: add successfully pasted directories
2030                            for(_iterator1 = successfulNodes[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2031                                node = _step1.value;
2032                                if (node["@type"] === "elpan:directory") {
2033                                    _this.addDirectoryToTree(targetPath, node.name);
2034                                }
2035                            }
2036                        } catch (err) {
2037                            _didIteratorError1 = true;
2038                            _iteratorError1 = err;
2039                        } finally{
2040                            try {
2041                                if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2042                                    _iterator1.return();
2043                                }
2044                            } finally{
2045                                if (_didIteratorError1) {
2046                                    throw _iteratorError1;
2047                                }
2048                            }
2049                        }
2050                        // For move operations, also remove source directories
2051                        if (operation === "move") {
2052                            _iteratorNormalCompletion2 = true, _didIteratorError2 = false, _iteratorError2 = undefined;
2053                            try {
2054                                for(_iterator2 = result.results[Symbol.iterator](); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true){
2055                                    r1 = _step2.value;
2056                                    if (r1.success && r1.sourceIdentifier) {
2057                                        sourcePath = decodeNodePath(r1.sourceIdentifier);
2058                                        if (sourcePath) {
2059                                            _this.removeDirectoryByPath(sourcePath);
2060                                        }
2061                                    }
2062                                }
2063                            } catch (err) {
2064                                _didIteratorError2 = true;
2065                                _iteratorError2 = err;
2066                            } finally{
2067                                try {
2068                                    if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
2069                                        _iterator2.return();
2070                                    }
2071                                } finally{
2072                                    if (_didIteratorError2) {
2073                                        throw _iteratorError2;
2074                                    }
2075                                }
2076                            }
2077                        }
2078                        // Show errors if any
2079                        if (errors.length > 0) {
2080                            _this.dispatch("operationError", {
2081                                detail: {
2082                                    type: operation,
2083                                    message: "Some items failed to ".concat(operation),
2084                                    error: errors.join("\n")
2085                                },
2086                                bubbles: true
2087                            });
2088                        }
2089                        // Notify browser about the paste operation
2090                        _this.dispatch("pasteComplete", {
2091                            detail: {
2092                                operation: operation,
2093                                targetPath: targetPath,
2094                                results: result.results
2095                            },
2096                            bubbles: true
2097                        });
2098                        return [
2099                            2
2100                        ];
2101                    });
2102                })();
2103            }
2104        },
2105        {
2106            key: "deleteDirectory",
2107            value: /**
2108     * Delete a directory (move to trash)
2109     */ function deleteDirectory(path) {
2110                var permanent = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
2111                var _this = this;
2112                return _async_to_generator(function() {
2113                    var node, confirmMessage, result, _tmp, removedIdentifiers, errorMessages, error;
2114                    return _ts_generator(this, function(_state) {
2115                        switch(_state.label){
2116                            case 0:
2117                                node = _this.findNodeByPath(path);
2118                                if (!node) return [
2119                                    2
2120                                ];
2121                                // Confirm deletion
2122                                confirmMessage = permanent ? 'Permanently delete "'.concat(node.name, '"? This cannot be undone.') : 'Move "'.concat(node.name, '" to trash?');
2123                                if (!window.confirm(confirmMessage)) {
2124                                    return [
2125                                        2
2126                                    ];
2127                                }
2128                                _state.label = 1;
2129                            case 1:
2130                                _state.trys.push([
2131                                    1,
2132                                    6,
2133                                    ,
2134                                    7
2135                                ]);
2136                                if (!permanent) return [
2137                                    3,
2138                                    3
2139                                ];
2140                                return [
2141                                    4,
2142                                    _this.service.permanentDeleteMultiple([
2143                                        node.id
2144                                    ])
2145                                ];
2146                            case 2:
2147                                _tmp = _state.sent();
2148                                return [
2149                                    3,
2150                                    5
2151                                ];
2152                            case 3:
2153                                return [
2154                                    4,
2155                                    _this.service.trashMultiple([
2156                                        node.id
2157                                    ])
2158                                ];
2159                            case 4:
2160                                _tmp = _state.sent();
2161                                _state.label = 5;
2162                            case 5:
2163                                result = _tmp;
2164                                // Check for success or already-gone items
2165                                removedIdentifiers = _to_consumable_array(result.success).concat(_to_consumable_array(result.notFound));
2166                                if (removedIdentifiers.includes(node.id)) {
2167                                    // Remove from tree
2168                                    _this.removeDirectoryByPath(path);
2169                                    // Dispatch event to notify browser
2170                                    _this.dispatch("directoryDeleted", {
2171                                        detail: {
2172                                            paths: [
2173                                                path
2174                                            ]
2175                                        },
2176                                        bubbles: true
2177                                    });
2178                                }
2179                                // Show errors if any
2180                                if (result.errors.length > 0) {
2181                                    errorMessages = result.errors.map(function(e) {
2182                                        return "".concat(e.identifier, ": ").concat(e.error);
2183                                    }).join("\n");
2184                                    _this.showError(new Error("Failed to delete:\n".concat(errorMessages)));
2185                                }
2186                                return [
2187                                    3,
2188                                    7
2189                                ];
2190                            case 6:
2191                                error = _state.sent();
2192                                _this.showError(error);
2193                                return [
2194                                    3,
2195                                    7
2196                                ];
2197                            case 7:
2198                                return [
2199                                    2
2200                                ];
2201                        }
2202                    });
2203                })();
2204            }
2205        },
2206        {
2207            /**
2208     * Check if clipboard has items
2209     */ key: "hasClipboard",
2210            value: function hasClipboard() {
2211                return this.clipboardIdentifiers.length > 0 && this.clipboardMode !== null;
2212            }
2213        },
2214        {
2215            /**
2216     * Clear the clipboard
2217     */ key: "clearClipboard",
2218            value: function clearClipboard() {
2219                this.clipboardPaths = [];
2220                this.clipboardIdentifiers = [];
2221                this.clipboardMode = null;
2222                this.dispatch("clipboardChange", {
2223                    detail: {
2224                        mode: null,
2225                        paths: [],
2226                        identifiers: [],
2227                        hasClipboard: false
2228                    },
2229                    bubbles: true
2230                });
2231            }
2232        },
2233        {
2234            /**
2235     * Set clipboard from external source (e.g., browser pane)
2236     */ key: "setClipboard",
2237            value: function setClipboard(paths, mode) {
2238                this.clipboardPaths = paths;
2239                // Note: identifiers should be set by the caller if cross-directory paste is needed
2240                this.clipboardMode = mode;
2241            }
2242        },
2243        {
2244            key: "contextMenuRename",
2245            value: /**
2246     * Context menu: Rename the selected directory
2247     */ function contextMenuRename() {
2248                var _this = this;
2249                return _async_to_generator(function() {
2250                    return _ts_generator(this, function(_state) {
2251                        switch(_state.label){
2252                            case 0:
2253                                _this.hideContextMenu();
2254                                // Only rename if we have a context menu path (not root)
2255                                if (_this.contextMenuPath === null || _this.contextMenuPath === "") {
2256                                    return [
2257                                        2
2258                                    ];
2259                                }
2260                                return [
2261                                    4,
2262                                    _this.startInPlaceRename(_this.contextMenuPath)
2263                                ];
2264                            case 1:
2265                                _state.sent();
2266                                return [
2267                                    2
2268                                ];
2269                        }
2270                    });
2271                })();
2272            }
2273        },
2274        {
2275            key: "startInPlaceRename",
2276            value: /**
2277     * Start in-place rename for the given path
2278     */ function startInPlaceRename(path) {
2279                var _this = this;
2280                return _async_to_generator(function() {
2281                    var _nameElement_parentElement, node, treeItem, nameElement, originalName, input, cancelled, handleBlur, handleKeydown, handleClick;
2282                    return _ts_generator(this, function(_state) {
2283                        // If already renaming, don't start another
2284                        if (_this.isRenamingInPlace) return [
2285                            2
2286                        ];
2287                        node = _this.findNodeByPath(path);
2288                        if (!node) return [
2289                            2
2290                        ];
2291                        // Find the tree item element for this path
2292                        treeItem = _this.treeTarget.querySelector('[data-file-manager--tree-item-path-value="'.concat(CSS.escape(path), '"]'));
2293                        if (!treeItem) return [
2294                            2
2295                        ];
2296                        // Find the name element within the item
2297                        nameElement = treeItem.querySelector(".file-tree__name");
2298                        if (!nameElement) return [
2299                            2
2300                        ];
2301                        originalName = node.name;
2302                        // Create input element for in-place editing
2303                        input = document.createElement("input");
2304                        input.type = "text";
2305                        input.className = "file-tree__rename-input";
2306                        input.value = originalName;
2307                        // Hide name element and insert input
2308                        nameElement.style.display = "none";
2309                        (_nameElement_parentElement = nameElement.parentElement) === null || _nameElement_parentElement === void 0 ? void 0 : _nameElement_parentElement.insertBefore(input, nameElement.nextSibling);
2310                        // Set up the input state
2311                        _this.isRenamingInPlace = true;
2312                        _this.renameInputElement = input;
2313                        // Track whether rename was cancelled to prevent blur handler from running
2314                        cancelled = false;
2315                        // Handle input events
2316                        handleBlur = function() {
2317                            if (cancelled) return;
2318                            _this.commitTreeRename(path, originalName, input.value.trim(), nameElement, input);
2319                        };
2320                        handleKeydown = function(e) {
2321                            if (e.key === "Enter") {
2322                                e.preventDefault();
2323                                e.stopPropagation();
2324                                input.blur(); // This will trigger handleBlur
2325                            } else if (e.key === "Escape") {
2326                                e.preventDefault();
2327                                e.stopPropagation();
2328                                cancelled = true;
2329                                input.removeEventListener("blur", handleBlur);
2330                                _this.cancelTreeRename(nameElement, input);
2331                            }
2332                            // Stop propagation to prevent tree keyboard navigation
2333                            e.stopPropagation();
2334                        };
2335                        // Prevent clicks from bubbling to the tree item
2336                        handleClick = function(e) {
2337                            e.stopPropagation();
2338                            e.preventDefault();
2339                        };
2340                        input.addEventListener("blur", handleBlur);
2341                        input.addEventListener("keydown", handleKeydown);
2342                        input.addEventListener("click", handleClick);
2343                        // Focus and select all text (directories don't have extensions)
2344                        input.focus();
2345                        input.select();
2346                        return [
2347                            2
2348                        ];
2349                    });
2350                })();
2351            }
2352        },
2353        {
2354            key: "commitTreeRename",
2355            value: /**
2356     * Commit the tree rename operation
2357     */ function commitTreeRename(path, originalName, newName, nameElement, input) {
2358                var _this = this;
2359                return _async_to_generator(function() {
2360                    var cleanup, node, result, _result_error, error;
2361                    return _ts_generator(this, function(_state) {
2362                        switch(_state.label){
2363                            case 0:
2364                                // Clean up the input
2365                                cleanup = function() {
2366                                    input.remove();
2367                                    nameElement.style.display = "";
2368                                    _this.isRenamingInPlace = false;
2369                                    _this.renameInputElement = null;
2370                                    _this.flushPendingRender();
2371                                };
2372                                // Check if user cancelled or entered the same name
2373                                if (newName === "" || newName === originalName) {
2374                                    cleanup();
2375                                    return [
2376                                        2
2377                                    ];
2378                                }
2379                                // Get the node to get its identifier
2380                                node = _this.findNodeByPath(path);
2381                                if (!node) {
2382                                    cleanup();
2383                                    return [
2384                                        2
2385                                    ];
2386                                }
2387                                _state.label = 1;
2388                            case 1:
2389                                _state.trys.push([
2390                                    1,
2391                                    4,
2392                                    ,
2393                                    5
2394                                ]);
2395                                return [
2396                                    4,
2397                                    _this.service.rename(node.id, newName)
2398                                ];
2399                            case 2:
2400                                result = _state.sent();
2401                                if (!result.success) {
2402                                    ;
2403                                    _this.showError(new Error((_result_error = result.error) !== null && _result_error !== void 0 ? _result_error : "Rename failed"));
2404                                    cleanup();
2405                                    return [
2406                                        2
2407                                    ];
2408                                }
2409                                // Reset rename state before refresh
2410                                _this.isRenamingInPlace = false;
2411                                _this.renameInputElement = null;
2412                                // Refresh the tree to reflect the change
2413                                return [
2414                                    4,
2415                                    _this.refresh()
2416                                ];
2417                            case 3:
2418                                _state.sent();
2419                                // Update selected path if needed
2420                                if (_this.selectedPath === path && result.newPath) {
2421                                    _this.selectedPath = result.newPath;
2422                                }
2423                                // Dispatch event to notify browser about the rename
2424                                _this.dispatch("directoryRenamed", {
2425                                    detail: {
2426                                        oldPath: path,
2427                                        newPath: result.newPath,
2428                                        newIdentifier: result.newIdentifier
2429                                    },
2430                                    bubbles: true
2431                                });
2432                                return [
2433                                    3,
2434                                    5
2435                                ];
2436                            case 4:
2437                                error = _state.sent();
2438                                _this.showError(error);
2439                                cleanup();
2440                                return [
2441                                    3,
2442                                    5
2443                                ];
2444                            case 5:
2445                                return [
2446                                    2
2447                                ];
2448                        }
2449                    });
2450                })();
2451            }
2452        },
2453        {
2454            key: "cancelTreeRename",
2455            value: /**
2456     * Cancel the tree rename operation
2457     */ function cancelTreeRename(nameElement, input) {
2458                input.remove();
2459                nameElement.style.display = "";
2460                this.isRenamingInPlace = false;
2461                this.renameInputElement = null;
2462                this.flushPendingRender();
2463                // Restore focus to the tree panel to keep keyboard shortcuts working
2464                this.element.focus();
2465            }
2466        },
2467        {
2468            key: "contextMenuNewFolder",
2469            value: // ==================== New Folder ====================
2470            /**
2471     * Context menu: New Folder
2472     */ function contextMenuNewFolder() {
2473                var _this = this;
2474                return _async_to_generator(function() {
2475                    var _this_contextMenuPath, _ref;
2476                    return _ts_generator(this, function(_state) {
2477                        switch(_state.label){
2478                            case 0:
2479                                _this.hideContextMenu();
2480                                return [
2481                                    4,
2482                                    _this.createNewFolder((_ref = (_this_contextMenuPath = _this.contextMenuPath) !== null && _this_contextMenuPath !== void 0 ? _this_contextMenuPath : _this.selectedPath) !== null && _ref !== void 0 ? _ref : "")
2483                                ];
2484                            case 1:
2485                                _state.sent();
2486                                return [
2487                                    2
2488                                ];
2489                        }
2490                    });
2491                })();
2492            }
2493        },
2494        {
2495            key: "createNewFolder",
2496            value: /**
2497     * Create a directory under `targetPath`, defaulting to the current tree
2498     * selection, and name it in place in the tree pane.
2499     *
2500     * The row carrying the input is a throwaway DOM node rather than a node in
2501     * the tree model: the tree shares its DirectoryNode objects with the
2502     * browser pane, so a placeholder in `children` would show up as a phantom
2503     * directory in the file listing too.
2504     */ function createNewFolder(targetPath) {
2505                var _this = this;
2506                return _async_to_generator(function() {
2507                    var _ref, parentPath, parentNode, parentItem, depth, row, nameElement, finish, input;
2508                    return _ts_generator(this, function(_state) {
2509                        switch(_state.label){
2510                            case 0:
2511                                if (_this.isRenamingInPlace) return [
2512                                    2
2513                                ];
2514                                parentPath = (_ref = targetPath !== null && targetPath !== void 0 ? targetPath : _this.selectedPath) !== null && _ref !== void 0 ? _ref : "";
2515                                parentNode = _this.findNodeByPath(parentPath);
2516                                if (!parentNode) return [
2517                                    2
2518                                ];
2519                                if (!!parentNode.isExpanded) return [
2520                                    3,
2521                                    2
2522                                ];
2523                                return [
2524                                    4,
2525                                    _this.toggleDirectory(parentPath)
2526                                ];
2527                            case 1:
2528                                _state.sent();
2529                                _state.label = 2;
2530                            case 2:
2531                                parentItem = _this.findItemElement(parentPath);
2532                                if (!parentItem) return [
2533                                    2
2534                                ];
2535                                depth = parseInt(parentItem.getAttribute("data-file-manager--tree-item-depth-value") || "0", 10) + 1;
2536                                row = _this.buildNewFolderRow(depth);
2537                                if (!row) return [
2538                                    2
2539                                ];
2540                                _this.getOrCreateChildrenList(parentItem).appendChild(row);
2541                                row.scrollIntoView({
2542                                    block: "nearest"
2543                                });
2544                                nameElement = row.querySelector(".file-tree__name");
2545                                if (!nameElement) {
2546                                    row.remove();
2547                                    return [
2548                                        2
2549                                    ];
2550                                }
2551                                finish = function() {
2552                                    _this.isRenamingInPlace = false;
2553                                    _this.renameInputElement = null;
2554                                    row.remove();
2555                                    _this.flushPendingRender();
2556                                };
2557                                input = setupInPlaceRename(nameElement, {
2558                                    originalName: NEW_FOLDER_NAME,
2559                                    isFile: false,
2560                                    onCommit: function() {
2561                                        var _ref = _async_to_generator(function(newName) {
2562                                            return _ts_generator(this, function(_state) {
2563                                                switch(_state.label){
2564                                                    case 0:
2565                                                        finish();
2566                                                        return [
2567                                                            4,
2568                                                            _this.commitNewFolder(parentNode, parentPath, newName)
2569                                                        ];
2570                                                    case 1:
2571                                                        _state.sent();
2572                                                        return [
2573                                                            2
2574                                                        ];
2575                                                }
2576                                            });
2577                                        });
2578                                        return function(newName) {
2579                                            return _ref.apply(this, arguments);
2580                                        };
2581                                    }(),
2582                                    onCancel: function() {
2583                                        finish();
2584                                        // Restore focus to the tree panel to keep keyboard shortcuts working
2585                                        _this.element.focus();
2586                                    }
2587                                }).input;
2588                                _this.isRenamingInPlace = true;
2589                                _this.renameInputElement = input;
2590                                return [
2591                                    2
2592                                ];
2593                        }
2594                    });
2595                })();
2596            }
2597        },
2598        {
2599            key: "commitNewFolder",
2600            value: /**
2601     * Create the directory the in-place input was named for
2602     */ function commitNewFolder(parentNode, parentPath, name) {
2603                var _this = this;
2604                return _async_to_generator(function() {
2605                    var fail, result, _result_error, error;
2606                    return _ts_generator(this, function(_state) {
2607                        switch(_state.label){
2608                            case 0:
2609                                fail = function(error) {
2610                                    _this.dispatch("operationError", {
2611                                        detail: {
2612                                            type: "mkdir",
2613                                            message: name,
2614                                            error: error
2615                                        },
2616                                        bubbles: true
2617                                    });
2618                                };
2619                                if (name.includes("/") || name.includes("\\")) {
2620                                    fail("Folder name cannot contain path separators");
2621                                    return [
2622                                        2
2623                                    ];
2624                                }
2625                                _state.label = 1;
2626                            case 1:
2627                                _state.trys.push([
2628                                    1,
2629                                    4,
2630                                    ,
2631                                    5
2632                                ]);
2633                                return [
2634                                    4,
2635                                    _this.service.createDirectory(parentNode.id, name)
2636                                ];
2637                            case 2:
2638                                result = _state.sent();
2639                                if (!result.success || !result.node) {
2640                                    ;
2641                                    fail((_result_error = result.error) !== null && _result_error !== void 0 ? _result_error : "Failed to create folder");
2642                                    return [
2643                                        2
2644                                    ];
2645                                }
2646                                return [
2647                                    4,
2648                                    _this.insertCreatedDirectory(parentNode, result.node)
2649                                ];
2650                            case 3:
2651                                _state.sent();
2652                                // Let the manager refresh the browser pane if it is showing the
2653                                // directory the new folder landed in
2654                                _this.dispatch("directoryCreated", {
2655                                    detail: {
2656                                        identifier: result.identifier,
2657                                        path: result.path,
2658                                        parentPath: parentPath,
2659                                        name: name
2660                                    },
2661                                    bubbles: true
2662                                });
2663                                return [
2664                                    3,
2665                                    5
2666                                ];
2667                            case 4:
2668                                error = _state.sent();
2669                                fail(error.message);
2670                                return [
2671                                    3,
2672                                    5
2673                                ];
2674                            case 5:
2675                                return [
2676                                    2
2677                                ];
2678                        }
2679                    });
2680                })();
2681            }
2682        },
2683        {
2684            key: "insertCreatedDirectory",
2685            value: /**
2686     * Add a freshly created directory to the tree under its parent
2687     */ function insertCreatedDirectory(parentNode, data) {
2688                var _this = this;
2689                return _async_to_generator(function() {
2690                    var node, loaded, error, _parentNode_children, children;
2691                    return _ts_generator(this, function(_state) {
2692                        switch(_state.label){
2693                            case 0:
2694                                node = FileSystemNode.fromData(data);
2695                                if (!node.isDirectory()) return [
2696                                    2
2697                                ];
2698                                parentNode.hasSubdirectory = true;
2699                                if (!!parentNode.hasLoadedChildren) return [
2700                                    3,
2701                                    4
2702                                ];
2703                                _state.label = 1;
2704                            case 1:
2705                                _state.trys.push([
2706                                    1,
2707                                    3,
2708                                    ,
2709                                    4
2710                                ]);
2711                                return [
2712                                    4,
2713                                    _this.service.loadDirectory(parentNode.id)
2714                                ];
2715                            case 2:
2716                                loaded = _state.sent();
2717                                parentNode.children = loaded.children;
2718                                _this.registerNode(parentNode);
2719                                return [
2720                                    3,
2721                                    4
2722                                ];
2723                            case 3:
2724                                error = _state.sent();
2725                                if (_instanceof(error, Error) && error.
2725name === "AbortError") return [
2726                                    2
2727                                ];
2728                                // The directory was created; the tree just cannot show it yet
2729                                _this.updateItemCanExpand(parentNode.path, true);
2730                                return [
2731                                    2
2732                                ];
2733                            case 4:
2734                                children = (_parentNode_children = parentNode.children) !== null && _parentNode_children !== void 0 ? _parentNode_children : [];
2735                                if (!children.some(function(child) {
2736                                    return child.path === node.path;
2737                                })) {
2738                                    parentNode.children = _to_consumable_array(children).concat([
2739                                        node
2740                                    ]);
2741                                }
2742                                parentNode.isExpanded = true;
2743                                _this.registerNode(node);
2744                                _this.render();
2745                                return [
2746                                    2
2747                                ];
2748                        }
2749                    });
2750                })();
2751            }
2752        },
2753        {
2754            key: "buildNewFolderRow",
2755            value: /**
2756     * Build the throwaway tree row that hosts the new folder's name input.
2757     * Reuses the tree item templates so it lines up with the real rows.
2758     */ function buildNewFolderRow(depth) {
2759                var _content_querySelector;
2760                var content = this.cloneItemTemplate("item-content");
2761                if (!content) return null;
2762                var wrapper = content.querySelector(".file-tree__item-content");
2763                if (wrapper) {
2764                    wrapper.style.paddingLeft = "".concat(depth * 16, "px");
2765                }
2766                // Non-expandable toggle, so the name lines up with its siblings
2767                var toggleSlot = content.querySelector('[data-slot="toggle"]');
2768                var toggle = this.cloneItemTemplate("toggle-disabled");
2769                if (toggleSlot && toggle) {
2770                    var chevronSlot = toggle.querySelector('[data-slot="chevron"]');
2771                    var chevron = this.cloneItemTemplate("chevron-placeholder");
2772                    if (chevronSlot && chevron) {
2773                        chevronSlot.replaceWith(chevron);
2774                    }
2775                    toggleSlot.replaceWith(toggle);
2776                }
2777                var iconSlot = content.querySelector('[data-slot="icon"]');
2778                var icon = this.cloneItemTemplate("folder-icon");
2779                if (iconSlot && icon) {
2780                    iconSlot.replaceWith(icon);
2781                }
2782                var nameSlot = content.querySelector('[data-slot="name"]');
2783                if (nameSlot) {
2784                    nameSlot.textContent = NEW_FOLDER_NAME;
2785                }
2786                (_content_querySelector = content.querySelector('[data-slot="loading"]')) === null || _content_querySelector === void 0 ? void 0 : _content_querySelector.remove();
2787                // The row is backed by no node, so strip everything that would have
2788                // Stimulus treat it as one
2789                var link = content.querySelector(".file-tree__link");
2790                if (link) {
2791                    link.removeAttribute("data-controller");
2792                    link.removeAttribute("data-action");
2793                    link.removeAttribute("href");
2794                }
2795                var item = document.createElement("li");
2796                item.className = "file-tree__item file-tree__item--new";
2797                item.appendChild(content);
2798                return item;
2799            }
2800        },
2801        {
2802            key: "cloneItemTemplate",
2803            value: /**
2804     * Clone one of the tree item templates
2805     */ function cloneItemTemplate(name) {
2806                var template = this.element.querySelector('template[data-tree-item-template="'.concat(name, '"]'));
2807                return template ? template.content.cloneNode(true) : null;
2808            }
2809        },
2810        {
2811            key: "getOrCreateChildrenList",
2812            value: /**
2813     * Get the children list of a tree item, creating it if the item has none
2814     */ function getOrCreateChildrenList(item) {
2815                var list = item.querySelector(":scope > .file-tree__children");
2816                if (!list) {
2817                    list = document.createElement("ul");
2818                    list.className = "file-tree__children";
2819                    item.appendChild(list);
2820                }
2821                return list;
2822            }
2823        },
2824        {
2825            /**
2826     * Context menu: Refresh
2827     * Dispatches requestRefresh event to manager for coordinated refresh
2828     */ key: "contextMenuRefresh",
2829            value: function contextMenuRefresh() {
2830                this.hideContextMenu();
2831                this.dispatch("requestRefresh", {
2832                    detail: {
2833                        source: "tree"
2834                    },
2835                    bubbles: true
2836                });
2837            }
2838        },
2839        {
2840            // ==================== Trash Operations ====================
2841            /**
2842     * Handle click on the trash tree item.
2843     * Dispatches a trashSelect event so the manager can navigate the browser to trash.
2844     */ key: "handleTrashClick",
2845            value: function handleTrashClick(event) {
2846                event.preventDefault();
2847                // Deselect any currently selected directory
2848                if (this.selectedPath !== null) {
2849                    this.setSelection(null);
2850                }
2851                this.isTrashSelected = true;
2852                this.render();
2853                this.dispatch("trashSelect", {
2854                    detail: {
2855                        identifier: this.trashRootIdentifierValue
2856                    },
2857                    bubbles: true
2858                });
2859            }
2860        },
2861        {
2862            /**
2863     * Handle context menu on the trash tree item
2864     */ key: "handleTrashContextMenu",
2865            value: function handleTrashContextMenu(event) {
2866                event.preventDefault();
2867                event.stopPropagation();
2868                this.showTrashContextMenu(event.clientX, event.clientY);
2869            }
2870        },
2871        {
2872            key: "showTrashContextMenu",
2873            value: /**
2874     * Show the trash-specific context menu
2875     */ function showTrashContextMenu(x, y) {
2876                if (!this.hasContextMenuTarget) return;
2877                var html = '<ul class="file-browser__context-menu-list">';
2878                html += '\n            <li class="file-browser__context-menu-item file-browser__context-menu-item--danger">\n                <button type="button" data-action="click->file-manager--tree#contextMenuEmptyTrash">\n                    <span class="context-menu__svg-icon" data-svg-url="'.concat(escapeHtml(this.iconTrashXValue), '" aria-hidden="true"></span>\n                    ').concat(escapeHtml(this.transEmptyTrashValue), "\n                </button>\n            </li>\n        ");
2879                html += "</ul>";
2880                this.contextMenuTarget.innerHTML = html;
2881                this.loadSvgPlaceholders(this.contextMenuTarget);
2882                positionContextMenu(this.contextMenuTarget, x, y);
2883            }
2884        },
2885        {
2886            /**
2887     * Context menu: Empty Trash
2888     */ key: "contextMenuEmptyTrash",
2889            value: function contextMenuEmptyTrash() {
2890                this.hideContextMenu();
2891                this.dispatch("emptyTrash", {
2892                    detail: {
2893                        identifier: this.trashRootIdentifierValue
2894                    },
2895                    bubbles: true
2896                });
2897            }
2898        },
2899        {
2900            /**
2901     * Select the trash node programmatically
2902     */ key: "selectTrash",
2903            value: function selectTrash() {
2904                if (this.selectedPath !== null) {
2905                    this.setSelection(null);
2906                }
2907                this.isTrashSelected = true;
2908                this.render();
2909            }
2910        },
2911        {
2912            /**
2913     * Deselect the trash node (called when navigating away from trash)
2914     */ key: "deselectTrash",
2915            value: function deselectTrash() {
2916                this.isTrashSelected = false;
2917                this.render();
2918            }
2919        },
2920        {
2921            /**
2922     * Handle drag start on a tree item
2923     */ key: "handleItemDragStart",
2924            value: function handleItemDragStart(event) {
2925                var item = event.target.closest(".file-tree__item");
2926                if (!item) return;
2927                var path = item.getAttribute("data-file-manager--tree-item-path-value");
2928                if (!path) return;
2929                this.isDragging = true;
2930                this.draggedPath = path;
2931                // Look up the node to get its identifier
2932                var node = this.findNodeByPath(path);
2933                var identifier = (node === null || node === void 0 ? void 0 : node.id) || (path === "" ? this.rootIdentifierValue : undefined);
2934                // Set the drag data with internal marker
2935                if (event.dataTransfer) {
2936                    event.dataTransfer.effectAllowed = "move";
2937                    // Store identifier for cross-pane operations (if we have it)
2938                    if (identifier) {
2939                        event.dataTransfer.setData("text/plain", JSON.stringify([
2940                            identifier
2941                        ]));
2942                    } else {
2943                        // Fallback to path if identifier not found (should not happen normally)
2944                        event.dataTransfer.setData("text/plain", JSON.stringify([
2945                            path
2946                        ]));
2947                    }
2948                    // Store path for local operations
2949                    event.dataTransfer.setData("application/x-file-manager-paths", JSON.stringify([
2950                        path
2951                    ]));
2952                    // Set a marker to identify internal drags (prevents upload dropzone from activating)
2953                    event.dataTransfer.setData("application/x-file-manager-internal", "true");
2954                }
2955                // Add dragging class to the item
2956                item.classList.add("file-tree__item--dragging");
2957            }
2958        },
2959        {
2960            /**
2961     * Handle drag end on a tree item
2962     */ key: "handleItemDragEnd",
2963            value: function handleItemDragEnd(event) {
2964                this.isDragging = false;
2965                this.draggedPath = null;
2966                // Remove dragging class from all items
2967                var items = this.element.querySelectorAll(".file-tree__item--dragging");
2968                items.forEach(function(item) {
2969                    return item.classList.remove("file-tree__item--dragging");
2970                });
2971                this.clearDropTargetStyling();
2972            }
2973        },
2974        {
2975            /**
2976     * Handle drag over on a tree item - show drop target indicator
2977     */ key: "handleItemDragOver",
2978            value: function handleItemDragOver(event) {
2979                var _event_dataTransfer;
2980                // Only accept internal file manager drags
2981                if (!((_event_dataTransfer = event.dataTransfer) === null || _event_dataTransfer === void 0 ? void 0 : _event_dataTransfer.types.includes("application/x-file-manager-internal"))) {
2982                    return;
2983                }
2984                event.preventDefault();
2985                event.stopPropagation();
2986                var item = event.target.closest(".file-tree__item");
2987                if (!item) return;
2988                // Clear previous drop targets
2989                this.clearDropTargetStyling();
2990                item.classList.add("file-tree__item--drop-target");
2991                if (event.dataTransfer) {
2992                    event.dataTransfer.dropEffect = "move";
2993                }
2994            }
2995        },
2996        {
2997            /**
2998     * Handle drag leave from a tree item
2999     */ key: "handleItemDragLeave",
3000            value: function handleItemDragLeave(event) {
3001                var item = event.target.closest(".file-tree__item");
3002                if (item) {
3003                    item.classList.remove("file-tree__item--drop-target");
3004                }
3005            }
3006        },
3007        {
3008            key: "handleItemDrop",
3009            value: /**
3010     * Handle drop on a tree item - dispatch event for manager to handle
3011     */ function handleItemDrop(event) {
3012                var _this = this;
3013                return _async_to_generator(function() {
3014                    var _event_dataTransfer, item, targetPath, sourceIdentifiers, _event_dataTransfer1, data, _event_dataTransfer2, targetNode, targetIdentifier, sourcePaths, _event_dataTransfer3, pathsData;
3015                    return _ts_generator(this, function(_state) {
3016                        // Only accept internal file manager drags
3017                        if (!((_event_dataTransfer = event.dataTransfer) === null || _event_dataTransfer === void 0 ? void 0 : _event_dataTransfer.types.includes("application/x-file-manager-internal"))) {
3018                            return [
3019                                2
3020                            ];
3021                        }
3022                        event.preventDefault();
3023                        event.stopPropagation();
3024                        item = event.target.closest(".file-tree__item");
3025                        if (!item) return [
3026                            2
3027                        ];
3028                        targetPath = item.getAttribute("data-file-manager--tree-item-path-value");
3029                        if (targetPath === null) return [
3030                            2
3031                        ];
3032                        // Clear drop styling
3033                        _this.clearDropTargetStyling();
3034                        item.classList.remove("file-tree__item--drop-target");
3035                        // Get the dragged identifiers from dataTransfer
3036                        sourceIdentifiers = [];
3037                        try {
3038                            ;
3039                            // First try the dedicated identifiers type
3040                            data = (_event_dataTransfer1 = event.dataTransfer) === null || _event_dataTransfer1 === void 0 ? void 0 : _event_dataTransfer1.getData("application/x-file-manager-identifiers");
3041                            if (data) {
3042                                sourceIdentifiers = JSON.parse(data);
3043                            } else {
3044                                ;
3045                                // Fallback to text/plain for backwards compatibility
3046                                data = (_event_dataTransfer2 = event.dataTransfer) === null || _event_dataTransfer2 === void 0 ? void 0 : _event_dataTransfer2.getData("text/plain");
3047                                if (data) {
3048                                    sourceIdentifiers = JSON.parse(data);
3049                                }
3050                            }
3051                        } catch (e) {
3052                            return [
3053                                2
3054                            ];
3055                        }
3056                        if (sourceIdentifiers.length === 0) return [
3057                            2
3058                        ];
3059                        // Look up the target node to get its identifier
3060                        targetNode = _this.findNodeByPath(targetPath);
3061                        targetIdentifier = (targetNode === null || targetNode === void 0 ? void 0 : targetNode.id) || (targetPath === "" ? _this.rootIdentifierValue : undefined);
3062                        if (!targetIdentifier) return [
3063                            2
3064                        ];
3065                        // Get source paths for local operations (tree updates)
3066                        sourcePaths = [];
3067                        try {
3068                            ;
3069                            pathsData = (_event_dataTransfer3 = event.dataTransfer) === null || _event_dataTransfer3 === void 0 ? void 0 : _event_dataTransfer3.getData("application/x-file-manager-paths");
3070                            if (pathsData) {
3071                                sourcePaths = JSON.parse(pathsData);
3072                            }
3073                        } catch (e) {
3074                        // Paths are optional, fall back to decoding from identifiers if needed
3075                        }
3076                        // Don't allow dropping onto a dragged item
3077                        if (sourcePaths.includes(targetPath)) return [
3078                            2
3079                        ];
3080                        // Dispatch event for manager controller to handle the move
3081                        _this.dispatch("dropMove", {
3082                            detail: {
3083                                sourceIdentifiers: sourceIdentifiers,
3084                                targetIdentifier: targetIdentifier,
3085                                sourcePaths: sourcePaths,
3086                                targetPath: targetPath
3087                            },
3088                            bubbles: true
3089                        });
3090                        return [
3091                            2
3092                        ];
3093                    });
3094                })();
3095            }
3096        },
3097        {
3098            key: "clearDropTargetStyling",
3099            value: /**
3100     * Clear drop target styling from all tree items
3101     */ function clearDropTargetStyling() {
3102                var dropTargets = this.element.querySelectorAll(".file-tree__item--drop-target");
3103                dropTargets.forEach(function(item) {
3104                    return item.classList.remove("file-tree__item--drop-target");
3105                });
3106            }
3107        },
3108        {
3109            // ==================== Incremental Tree Updates ====================
3110            /**
3111     * Remove a directory from the tree by path (used after move operations)
3112     * @param path The path of the directory to remove
3113     */ key: "removeDirectoryByPath",
3114            value: function removeDirectoryByPath(path) {
3115                if (!this.rootNode) {
3116                    return;
3117                }
3118                // Find the parent of the node to remove
3119                var parentPath = getParentPath(path);
3120                // If parentPath is empty, the directory is at root level - use rootNode
3121                var parentNode = parentPath === "" ? this.rootNode : this.findNodeByPath(parentPath);
3122                if (parentNode && parentNode.children) {
3123                    // Remove the node from parent's children
3124                    parentNode.children = parentNode.children.filter(function(child) {
3125                        return child.path !== path;
3126                    });
3127                    // Update hasSubdirectory flag if no more subdirectories
3128                    var hasSubdirs = parentNode.children.some(function(child) {
3129                        return child.isDirectory();
3130                    });
3131                    parentNode.hasSubdirectory = hasSubdirs;
3132                    // Re-render the tree
3133                    this.render();
3134                }
3135                // Also remove the DOM element directly for immediate feedback
3136                var itemElement = this.findItemElement(path);
3137                if (itemElement) {
3138                    itemElement.remove();
3139                }
3140            }
3141        },
3142        {
3143            /**
3144     * Add a directory to the tree (used after move/copy operations)
3145     * @param parentPath The path where to add the new directory
3146     * @param name The name of the new directory
3147     */ key: "addDirectoryToTree",
3148            value: function addDirectoryToTree(parentPath, name) {
3149                if (!this.rootNode) return;
3150                var parentNode = this.findNodeByPath(parentPath);
3151                if (!parentNode) return;
3152                // Construct the new path
3153                var newPath = parentPath ? "".concat(parentPath, "/").concat(name) : name;
3154                // If parent hasn't loaded children yet, just update canExpand flag
3155                // The directory will appear when user expands the parent (loads from server)
3156                if (!parentNode.hasLoadedChildren) {
3157                    // Ensure the parent shows as expandable
3158                    parentNode.hasSubdirectory = true;
3159                    // Update the toggle visibility in the DOM
3160                    this.updateItemCanExpand(parentPath, true);
3161                    return;
3162                }
3163                // Check if directory already exists
3164                if (parentNode.children) {
3165                    var exists = parentNode.children.some(function(child) {
3166                        return child.path === newPath;
3167                    });
3168                    if (exists) return; // Already exists, no need to add
3169                }
3170                // Create new directory node
3171                var newNode = new DirectoryNode({
3172                    path: newPath,
3173                    name: name,
3174                    type: "directory",
3175                    size: null,
3176                    modified: new Date().toISOString(),
3177                    permissions: null,
3178                    owner: null,
3179                    hasSubdirectories: false
3180                });
3181                // Add to parent's children (parent has loaded children, safe to add)
3182                if (!parentNode.children) {
3183                    parentNode.children = [];
3184                }
3185                parentNode.children.push(newNode);
3186                // Update hasSubdirectory flag
3187                parentNode.hasSubdirectory = true;
3188                // Re-render if parent is expanded
3189                if (parentNode.isExpanded) {
3190                    this.render();
3191                }
3192            }
3193        }
3194    ]);
3195    return TreeController;
3196}(Controller);
3197_define_property(TreeController, "targets", [
3198    "tree",
3199    "loading",
3200    "error",
3201    "contextMenu"
3202]);
3203_define_property(TreeController, "values", {
3204    rootIdentifier: String,
3205    trashRootIdentifier: {
3206        type: String,
3207        default: ""
3208    },
3209    // Skip auto-loading the root directory on connect (let manager control initial load)
3210    skipAutoLoad: {
3211        type: Boolean,
3212        default: false
3213    },
3214    // Translation values
3215    transError: {
3216        type: String,
3217        default: "Error: %message%"
3218    },
3219    transOpen: {
3220        type: String,
3221        default: "Open"
3222    },
3223    transNewFolder: {
3224        type: String,
3225        default: "New Folder"
3226    },
3227    transRename: {
3228        type: String,
3229        default: "Rename"
3230    },
3231    transDelete: {
3232        type: String,
3233        default: "Delete"
3234    },
3235    transRefresh: {
3236        type: String,
3237        default: "Refresh"
3238    },
3239    transCopy: {
3240        type: String,
3241        default: "Copy"
3242    },
3243    transCut: {
3244        type: String,
3245        default: "Cut"
3246    },
3247    transPaste: {
3248        type: String,
3249        default: "Paste"
3250    },
3251    transTrash: {
3252        type: String,
3253        default: "Trash"
3254    },
3255    transRestore: {
3256        type: String,
3257        default: "Restore"
3258    },
3259    transDeletePermanently: {
3260        type: String,
3261        default: "Delete Permanently"
3262    },
3263    transEmptyTrash: {
3264        type: String,
3265        default: "Empty Trash"
3266    },
3267    // Icon URLs
3268    iconPlayerPlay: {
3269        type: String,
3270        default: ""
3271    },
3272    iconFolderPlus: {
3273        type: String,
3274        default: ""
3275    },
3276    iconCut: {
3277        type: String,
3278        default: ""
3279    },
3280    iconCopy: {
3281        type: String,
3282        default: ""
3283    },
3284    iconClipboardCopy: {
3285        type: String,
3286        default: ""
3287    },
3288    iconPencil: {
3289        type: String,
3290        default: ""
3291    },
3292    iconTrash: {
3293        type: String,
3294        default: ""
3295    },
3296    iconRestore: {
3297        type: String,
3298        default: ""
3299    },
3300    iconTrashX: {
3301        type: String,
3302        default: ""
3303    },
3304    iconRefresh: {
3305        type: String,
3306        default: ""
3307    }
3308});
3309/**
3310 * FileTree Controller
3311 * 
3312 * Displays a collapsible tree view of directories in the left pane.
3313 * Uses semantic ul > li structure with tree-item sub-controllers.
3314 * Dispatches 'directory:select' events when a directory is clicked.
3315 * 
3316 * Controller identifier: file-manager--tree
3317 * 
3318 * @example
3319 * <div data-controller="file-manager--tree"
3320 *      data-file-manager--tree-filesystem-type-value="account"
3321 *      data-file-manager--tree-filesystem-identifier-value="abc123"
3322 *      data-file-manager--tree-root-path-value=""
3323 *      data-action="keydown->file-manager--tree#handleKeydown
3324 *                   file-manager--tree-item:select->file-manager--tree#handleItemSelect
3325 *                   file-manager--tree-item:dblselect->file-manager--tree#handleItemDblSelect
3326 *                   file-manager--tree-item:toggle->file-manager--tree#handleItemToggle
3327 *                   file-manager--tree-item:contextmenu->file-manager--tree#handleItemContextMenu">
3328 *   <ul data-file-manager--tree-target="tree" class="file-tree__list"></ul>
3329 *   <div data-file-manager--tree-target="loading" class="hidden">Loading...</div>
3330 *   <div data-file-manager--tree-target="error" class="hidden"></div>
3331 * </div>
3332 */ export { TreeController as default };

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.