(path, opts = {})
| 4181 | |
| 4182 | // Async variant that loads children as it expands so deep paths become visible. |
| 4183 | export async function expandTreePathAsync(path, opts = {}) { |
| 4184 | const { force = false, persist = false, includeLeaf = false } = opts; |
| 4185 | const state = loadFolderTreeState(); |
| 4186 | const parts = (path || '').split('/').filter(Boolean); |
| 4187 | let cumulative = ''; |
| 4188 | const lastIndex = includeLeaf ? parts.length - 1 : Math.max(0, parts.length - 2); |
| 4189 | |
| 4190 | for (let i = 0; i < parts.length; i++) { |
| 4191 | cumulative = i === 0 ? parts[i] : `${cumulative}/${parts[i]}`; |
| 4192 | if (i > lastIndex) break; |
| 4193 | const option = document.querySelector(`.folder-option[data-folder="${CSS.escape(cumulative)}"]`); |
| 4194 | if (!option) continue; |
| 4195 | const li = option.closest('li[role="treeitem"]'); |
| 4196 | const nestedUl = li ? li.querySelector(':scope > ul') : null; |
| 4197 | if (!nestedUl) continue; |
| 4198 | const shouldExpand = force || state[cumulative] === 'block'; |
| 4199 | nestedUl.classList.toggle('expanded', shouldExpand); |
| 4200 | nestedUl.classList.toggle('collapsed', !shouldExpand); |
| 4201 | li.setAttribute('aria-expanded', String(!!shouldExpand)); |
| 4202 | if (persist && shouldExpand) state[cumulative] = 'block'; |
| 4203 | if (shouldExpand) { |
| 4204 | try { await ensureChildrenLoaded(cumulative, nestedUl); } catch (e) {} |
| 4205 | } |
| 4206 | } |
| 4207 | if (persist) saveFolderTreeState(state); |
| 4208 | } |
| 4209 | |
| 4210 | /* ---------------------- |
| 4211 | Wire toolbar buttons that were inert (rename/delete) |
no test coverage detected