diff --git a/app/templates/library.html b/app/templates/library.html
index c629e4b..b31f19e 100644
--- a/app/templates/library.html
+++ b/app/templates/library.html
@@ -220,7 +220,7 @@
Last edited
Last visited
-
@@ -313,12 +313,13 @@ function libraryPage() {
peekFavorited: false,
peekMoreOpen: false,
- // ── Computed flat list (NOT a getter — Alpine 3.14.9 bug) ──
+ // ── Computed flat list ──
flatItems: [],
- tableHtml: '',
- _buildTableHtml() {
+ _renderTable() {
var self = this;
+ var body = document.getElementById('lib-table-body');
+ if (!body) return;
var html = '';
for (var i = 0; i < this.flatItems.length; i++) {
var item = this.flatItems[i];
@@ -346,7 +347,7 @@ function libraryPage() {
html += '' + (item.icon || '\ud83d\udcc4') + '';
// Title or rename input
if (isRenaming) {
- html += '';
+ html += '';
} else {
html += '' + self._escHtml(item.title) + '';
}
@@ -365,7 +366,7 @@ function libraryPage() {
html += '' + self.formatTime(item.visited_at) + '
';
html += '';
}
- this.tableHtml = html;
+ body.innerHTML = html;
},
_escHtml(s) { var d=document.createElement('div'); d.textContent = s||''; return d.innerHTML; },
@@ -384,7 +385,7 @@ function libraryPage() {
this.flatItems.splice(0, this.flatItems.length, ...result);
this.selectedCount = Object.keys(this.selected).length;
this.allSelected = this.flatItems.length > 0 && this.selectedCount === this.flatItems.length;
- this._buildTableHtml();
+ this._renderTable();
},
// ── Global dispatch (bypasses Alpine x-for reactivity issues) ──
@@ -405,7 +406,10 @@ function libraryPage() {
},
commitRenameById(id) {
var item = this._findItem(id);
- if (!item) { this.renamingId = null; this._buildTableHtml(); return; }
+ if (!item) { this.renamingId = null; this._renderTable(); return; }
+ // Read value from the input
+ var inp = document.getElementById('rename-inp-' + id);
+ if (inp) this.renameValue = inp.value;
this.commitRename(item);
},
openItemById(id) {
@@ -524,7 +528,7 @@ function libraryPage() {
console.log('[Library] loaded ' + this.items.length + ' items');
this._markTree(this.items, 0);
this._recomputeFlatItems();
- this._buildTableHtml();
+ this._renderTable();
console.log('[Library] flatItems after recompute: ' + this.flatItems.length);
// Force Alpine to re-render (known issue with x-for in 3.14.9)
var self = this;
@@ -568,7 +572,7 @@ function libraryPage() {
delete this.expanded[item.id];
this.expanded = Object.assign({}, this.expanded);
this._recomputeFlatItems();
- this._buildTableHtml();
+ this._renderTable();
return;
}
// Expand — load children if not loaded yet
@@ -586,7 +590,7 @@ function libraryPage() {
}
}
this._recomputeFlatItems();
- this._buildTableHtml();
+ this._renderTable();
},
_markChildren(nodes, depth) {
@@ -608,7 +612,7 @@ function libraryPage() {
}
this.selected = Object.assign({}, this.selected);
this._recomputeFlatItems();
- this._buildTableHtml();
+ this._renderTable();
},
toggleSelectAll() {
@@ -622,14 +626,14 @@ function libraryPage() {
this.selected = s;
}
this._recomputeFlatItems();
- this._buildTableHtml();
+ this._renderTable();
},
clearSelection() {
this.selected = {};
this.moreOpen = false;
this._recomputeFlatItems();
- this._buildTableHtml();
+ this._renderTable();
},
// ── Multi-select actions ──
@@ -678,22 +682,18 @@ function libraryPage() {
startRename(item) {
this.renamingId = item.id;
this.renameValue = item.title;
- this._buildTableHtml();
- var self = this;
- this.$nextTick(function() {
- var inp = document.querySelector('.row-title input, [onkeydown*=\"commitRenameById\"]');
- // Try to find the rename input that was just created
- var inputs = document.querySelectorAll('#lib-table-body input');
- for (var i = 0; i < inputs.length; i++) {
- if (inputs[i].value === item.title) { inputs[i].focus(); inputs[i].select(); break; }
- }
- });
+ this._renderTable();
+ // Focus the rename input
+ setTimeout(function() {
+ var inp = document.getElementById('rename-inp-' + item.id);
+ if (inp) { inp.focus(); inp.select(); }
+ }, 50);
},
async commitRename(item) {
var newName = (this.renameValue || '').trim();
this.renamingId = null;
- if (!newName || newName === item.title) { this._buildTableHtml(); return; }
+ if (!newName || newName === item.title) { this._renderTable(); return; }
try {
var r = await fetch('/api/pages/' + item.id + '/rename', {
method:'PUT', headers:{'Content-Type':'application/json'},
@@ -703,7 +703,7 @@ function libraryPage() {
item.title = newName;
}
} catch(e) {}
- this._buildTableHtml();
+ this._renderTable();
},
// ── Add new ──
@@ -834,44 +834,5 @@ function libraryPage() {
}
};
}
-// SortableJS — drag-and-drop reorder in library table
-document.addEventListener('alpine:init', function() {
- var initSortable = function() {
- var body = document.getElementById('lib-table-body');
- if (!body || typeof Sortable === 'undefined') return;
- // Clean up any existing instance
- if (body._sortable) body._sortable.destroy();
- body._sortable = new Sortable(body, {
- handle: '.drag-handle',
- animation: 150,
- ghostClass: 'sortable-ghost',
- onEnd: async function(evt) {
- var itemEl = evt.item;
- var itemId = itemEl.getAttribute('data-lib-id');
- var prevEl = evt.item.previousElementSibling;
- var nextEl = evt.item.nextElementSibling;
- var prevId = prevEl ? prevEl.getAttribute('data-lib-id') : null;
- var nextId = nextEl ? nextEl.getAttribute('data-lib-id') : null;
- if (!itemId) return;
- try {
- await fetch('/api/pages/' + itemId + '/move', {
- method: 'PUT',
- headers: {'Content-Type': 'application/json'},
- body: JSON.stringify({before_id: nextId || null, after_id: prevId || null})
- });
- } catch(e) {}
- }
- });
- };
- // Watch for table body updates with MutationObserver
- var target = document.getElementById('lib-table');
- if (target) {
- var observer = new MutationObserver(function() {
- setTimeout(initSortable, 200);
- });
- observer.observe(target, {childList: true, subtree: true});
- }
- initSortable();
-});
{% endblock %}