{ "version": 3, "sources": ["../../javascript/sidebar.js", "../../javascript/notifications.js", "../../javascript/koz_dropdown.js", "../../javascript/koz_choices_editor.js", "../../javascript/task_modal.js", "../../javascript/block_editor.js", "../../javascript/page_actions.js"], "sourcesContent": ["// Kozado Sidebar JavaScript\n// Handles sidebar interactivity, workspace switching, dropdowns, etc.\n\ndocument.addEventListener('DOMContentLoaded', function() {\n // ============================================\n // SIDEBAR TOGGLE (Collapse/Expand)\n // ============================================\n\n const sidebarToggle = document.getElementById('sidebar-toggle');\n const primarySidebar = document.getElementById('primary-sidebar');\n const navbarLogoSection = document.getElementById('navbar-logo-section');\n\n if (sidebarToggle && primarySidebar && navbarLogoSection) {\n sidebarToggle.addEventListener('click', function() {\n // Toggle both sidebar and navbar logo section\n primarySidebar.classList.toggle('collapsed');\n navbarLogoSection.classList.toggle('collapsed');\n\n // Save preference\n const isCollapsed = primarySidebar.classList.contains('collapsed');\n localStorage.setItem('kozado_sidebar_collapsed', isCollapsed);\n });\n\n // Restore preference\n const savedState = localStorage.getItem('kozado_sidebar_collapsed');\n if (savedState === 'true') {\n primarySidebar.classList.add('collapsed');\n navbarLogoSection.classList.add('collapsed');\n }\n }\n \n // ============================================\n // WORKSPACE DROPDOWN\n // ============================================\n \n const workspaceDropdownBtn = document.getElementById('workspace-dropdown-btn');\n const workspaceDropdown = document.getElementById('workspace-dropdown');\n \n function closeWorkspaceDropdown() {\n if (workspaceDropdown) {\n workspaceDropdown.classList.remove('show');\n workspaceDropdown.classList.add('hidden');\n }\n }\n\n if (workspaceDropdownBtn && workspaceDropdown) {\n workspaceDropdownBtn.addEventListener('click', function(e) {\n e.stopPropagation();\n workspaceDropdown.classList.toggle('show');\n workspaceDropdown.classList.toggle('hidden');\n });\n \n // Close dropdown when clicking outside\n document.addEventListener('click', function(e) {\n if (!workspaceDropdown.contains(e.target) && !workspaceDropdownBtn.contains(e.target)) {\n closeWorkspaceDropdown();\n }\n });\n \n // Workspace switching\n const workspaceSwitchItems = document.querySelectorAll('.workspace-switch-item');\n workspaceSwitchItems.forEach(item => {\n item.addEventListener('click', function() {\n const slug = this.dataset.workspaceSlug;\n if (slug) {\n window.location.href = '/workspaces/' + slug;\n }\n });\n });\n }\n \n // ============================================\n // PROJECT TREE TOGGLE\n // ============================================\n // Handled inline by _sidebar.html.erb (single source of truth for collapse,\n // icon rotation, and localStorage persistence).\n\n\n // ============================================\n // QUICK SEARCH OVERLAY\n // ============================================\n \n const quickSearchBtn = document.getElementById('quick-search-btn');\n const headerSearchBtn = document.getElementById('header-search-btn');\n const searchOverlay = document.getElementById('search-overlay');\n const globalSearchInput = document.getElementById('global-search-input');\n \n function openSearch() {\n if (searchOverlay) {\n searchOverlay.classList.remove('hidden');\n if (globalSearchInput) {\n globalSearchInput.focus();\n }\n }\n }\n \n function closeSearch() {\n if (searchOverlay) {\n searchOverlay.classList.add('hidden');\n if (globalSearchInput) {\n globalSearchInput.value = '';\n }\n }\n }\n \n if (quickSearchBtn) {\n quickSearchBtn.addEventListener('click', openSearch);\n }\n \n if (headerSearchBtn) {\n headerSearchBtn.addEventListener('click', openSearch);\n }\n \n if (searchOverlay) {\n searchOverlay.addEventListener('click', function(e) {\n if (e.target === searchOverlay) {\n closeSearch();\n }\n });\n }\n \n // Keyboard shortcuts\n document.addEventListener('keydown', function(e) {\n // Cmd/Ctrl + K to open search\n if ((e.metaKey || e.ctrlKey) && e.key === 'k') {\n e.preventDefault();\n if (searchOverlay && searchOverlay.classList.contains('hidden')) {\n openSearch();\n } else {\n closeSearch();\n }\n }\n \n // Escape to close overlays\n if (e.key === 'Escape') {\n closeSearch();\n closeNotifications();\n closeUserDropdown();\n closeWorkspaceDropdown();\n }\n });\n \n // ============================================\n // NOTIFICATIONS PANEL\n // ============================================\n \n const notificationsBtn = document.getElementById('notifications-btn');\n const notificationsPanel = document.getElementById('notifications-panel');\n \n function closeNotifications() {\n if (notificationsPanel) {\n notificationsPanel.classList.add('hidden');\n }\n }\n \n if (notificationsBtn && notificationsPanel) {\n notificationsBtn.addEventListener('click', function(e) {\n e.stopPropagation();\n notificationsPanel.classList.toggle('hidden');\n });\n \n document.addEventListener('click', function(e) {\n if (!notificationsPanel.contains(e.target) && !notificationsBtn.contains(e.target)) {\n closeNotifications();\n }\n });\n }\n \n // ============================================\n // USER DROPDOWN\n // ============================================\n \n const userDropdownBtn = document.getElementById('user-dropdown-btn');\n const userDropdown = document.getElementById('user-dropdown');\n \n function closeUserDropdown() {\n if (userDropdown) {\n userDropdown.classList.add('hidden');\n }\n }\n \n if (userDropdownBtn && userDropdown) {\n userDropdownBtn.addEventListener('click', function(e) {\n e.stopPropagation();\n userDropdown.classList.toggle('hidden');\n });\n \n document.addEventListener('click', function(e) {\n if (!userDropdown.contains(e.target) && !userDropdownBtn.contains(e.target)) {\n closeUserDropdown();\n }\n });\n }\n \n // ============================================\n // ALERT CLOSE BUTTONS\n // ============================================\n \n const closeAlertButtons = document.querySelectorAll('.close-alert');\n closeAlertButtons.forEach(btn => {\n btn.addEventListener('click', function() {\n const alert = this.closest('.alert');\n if (alert) {\n alert.style.opacity = '0';\n setTimeout(() => alert.remove(), 300);\n }\n });\n });\n \n // ============================================\n // NEW PROJECT BUTTON\n // ============================================\n // Handled inline by the new-project modal in _sidebar.html.erb.\n\n\n // ============================================\n // TOOLTIP INITIALIZATION (if needed)\n // ============================================\n \n // Add tooltips to buttons with title attribute\n const tooltipElements = document.querySelectorAll('[title]');\n tooltipElements.forEach(el => {\n // Could initialize a tooltip library here\n });\n \n console.log('Kozado sidebar initialized');\n});\n", "// Kozado \u2014 global Notifications panel.\n//\n// Powers the bell button + panel in the navbar. Reads bootstrap data from\n// #notifications-panel (rendered by application.html.erb), fetches the\n// current user's notifications, paints them into the panel, toggles the\n// red unread dot on the bell, subscribes to the per-user Pusher channel\n// for live additions, and wires the \"Mark all read\" button.\n//\n// The toggle (open/close on bell click, ESC, outside click) is handled by\n// app/javascript/sidebar.js \u2014 this file is only concerned with data and\n// rendering.\n\n(function () {\n function init() {\n var panel = document.getElementById('notifications-panel');\n if (!panel) return;\n\n var currentUserId = parseInt(panel.dataset.currentUserId, 10);\n var pusherKey = panel.dataset.pusherKey;\n var pusherCluster = panel.dataset.pusherCluster || 'us2';\n\n var btn = document.getElementById('notifications-btn');\n var dot = document.getElementById('notifications-unread-dot');\n var listEl = document.getElementById('notifications-list');\n var emptyEl = document.getElementById('notifications-empty');\n var markAllBtn = document.getElementById('notifications-mark-all-read');\n\n if (!currentUserId || !listEl) return;\n\n var notifications = [];\n var unreadCount = 0;\n\n function updateDot() {\n if (!dot) return;\n if (unreadCount > 0) dot.classList.remove('hidden');\n else dot.classList.add('hidden');\n // Mirror the unread count to any listening desktop wrapper (Electron app\n // listens for this via its preload bridge). No-op in regular browsers.\n try {\n window.dispatchEvent(new CustomEvent('kozado:unread-count', { detail: unreadCount }));\n } catch (e) { /* ignore */ }\n }\n\n function updateMarkAllState() {\n if (!markAllBtn) return;\n markAllBtn.disabled = unreadCount === 0;\n }\n\n function escapeHtml(s) {\n return String(s == null ? '' : s)\n .replace(/&/g, '&').replace(//g, '>').replace(/\"/g, '"').replace(/'/g, ''');\n }\n\n // Color cue for the actor avatar fallback. Hashing on actor id keeps a\n // user's chip the same color across notifications without needing a\n // server-side color table.\n var GRADIENTS = [\n 'from-brand to-brand-2',\n 'from-purple to-blue',\n 'from-amber to-pink',\n 'from-green to-teal-400',\n 'from-pink to-purple',\n 'from-blue to-cyan-400'\n ];\n function gradientFor(id) {\n var n = (parseInt(id, 10) || 0) % GRADIENTS.length;\n return GRADIENTS[n < 0 ? n + GRADIENTS.length : n];\n }\n\n function renderItem(n) {\n var actor = n.actor || {};\n var initials = escapeHtml(actor.initials || (actor.name ? actor.name.slice(0, 2).toUpperCase() : '\u00B7'));\n var avatar;\n if (actor.image) {\n avatar =\n '
' +\n '' + initials + '' +\n '\"\"' +\n '
';\n } else {\n avatar =\n '
' +\n '' + initials + '' +\n '
';\n }\n\n var unreadDot = n.read\n ? ''\n : '';\n\n var bodyHtml = n.body\n ? '
' + escapeHtml(n.body) + '
'\n : '';\n\n var rowClasses = 'p-4 hover:bg-bg-3 cursor-pointer flex items-start gap-3' +\n (n.read ? '' : ' bg-bg-2/[0.025]');\n\n return (\n '
' +\n avatar +\n '
' +\n '
' + escapeHtml(n.title) + '
' +\n bodyHtml +\n '
' + escapeHtml(n.created_at_human || '') + '
' +\n '
' +\n unreadDot +\n '
'\n );\n }\n\n function render() {\n if (notifications.length === 0) {\n listEl.innerHTML = '
No notifications yet.
';\n return;\n }\n listEl.innerHTML = notifications.map(renderItem).join('');\n }\n\n function applyState(items, count) {\n notifications = Array.isArray(items) ? items : [];\n unreadCount = typeof count === 'number' ? count : notifications.filter(function (n) { return !n.read; }).length;\n render();\n updateDot();\n updateMarkAllState();\n }\n\n function fetchNotifications() {\n return fetch('/api/notifications', {\n credentials: 'same-origin',\n headers: { 'Accept': 'application/json' }\n })\n .then(function (r) { return r.ok ? r.json() : null; })\n .then(function (data) {\n if (!data) return;\n applyState(data.notifications || [], data.unread_count || 0);\n })\n .catch(function () { /* leave whatever's already rendered */ });\n }\n\n // Click handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n listEl.addEventListener('click', function (e) {\n var row = e.target.closest('[data-id]');\n if (!row) return;\n var id = row.getAttribute('data-id');\n var url = row.getAttribute('data-url');\n\n // Optimistically mark the row as read in the panel even if the server\n // fire-and-forget call fails \u2014 the next fetch will reconcile.\n var wasUnread = row.querySelector('[aria-label=\"unread\"]') !== null;\n if (wasUnread) {\n var dotSpan = row.querySelector('[aria-label=\"unread\"]');\n if (dotSpan) dotSpan.remove();\n row.classList.remove('bg-bg-2/[0.025]');\n unreadCount = Math.max(0, unreadCount - 1);\n updateDot();\n updateMarkAllState();\n }\n\n fetch('/api/notifications/' + encodeURIComponent(id) + '/mark_read', {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'Accept': 'application/json' }\n }).catch(function () { /* ignore */ });\n\n if (url) window.location.href = url;\n });\n\n if (markAllBtn) {\n markAllBtn.addEventListener('click', function (e) {\n e.stopPropagation();\n if (markAllBtn.disabled) return;\n fetch('/api/notifications/mark_all_read', {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'Accept': 'application/json' }\n })\n .then(function (r) { return r.ok ? r.json() : null; })\n .then(function () {\n // Re-fetch to pick up read_at on each row (and so the order/\n // styling is consistent with what other tabs/devices see).\n return fetchNotifications();\n })\n .catch(function () { /* ignore */ });\n });\n }\n\n // Refresh when the panel is opened so the user sees the freshest list.\n if (btn) {\n btn.addEventListener('click', function () {\n // sidebar.js toggles `.hidden` synchronously on this same click \u2014\n // by the time this handler runs it reflects the new state.\n if (!panel.classList.contains('hidden')) fetchNotifications();\n });\n }\n\n // Live updates via Pusher \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (pusherKey && typeof Pusher !== 'undefined') {\n try {\n var pusher = new Pusher(pusherKey, { cluster: pusherCluster });\n var channel = pusher.subscribe('user-' + currentUserId);\n channel.bind('new-notification', function (data) {\n if (!data || !data.notification) return;\n var n = data.notification;\n notifications.unshift(n);\n if (notifications.length > 50) notifications.length = 50;\n if (!n.read) unreadCount += 1;\n render();\n updateDot();\n updateMarkAllState();\n // Forward to a desktop wrapper (Electron) if one is listening.\n try {\n window.dispatchEvent(new CustomEvent('kozado:notification', {\n detail: {\n title: n.title || 'Kozado',\n body: n.body || '',\n tag: 'notification-' + n.id,\n url: n.url || '',\n unreadCount: unreadCount\n }\n }));\n } catch (e) { /* ignore */ }\n });\n } catch (e) { /* ignore */ }\n }\n\n // Initial paint\n fetchNotifications();\n }\n\n // Loaded with `defer`; DOM is parsed by the time we run.\n init();\n})();\n", "// Kozado custom dropdown + color palette utilities.\n//\n// `window.KozColors` is the canonical 7-color palette mirrored from\n// DataTableColumn::SELECT_COLORS on the server. It powers status chips,\n// column accents, and the color picker UI everywhere selectable colors appear.\n//\n// `window.createKdd()` builds a styled dropdown that renders against the dark\n// canvas. Used as a drop-in replacement for native ' +\n '
' +\n '
' +\n '' +\n '
';\n\n document.body.appendChild(pop);\n\n const search = pop.querySelector('.tm-tag-pop-search');\n const listEl = pop.querySelector('.tm-tag-pop-list');\n const createWrap = pop.querySelector('.tm-tag-pop-create');\n const createBtn = pop.querySelector('.tm-tag-pop-create-btn');\n const createLabel = pop.querySelector('.tm-tag-pop-create-label');\n\n const renderList = () => {\n listEl.innerHTML = '';\n if (!this._boardTags.length) {\n const empty = document.createElement('div');\n empty.className = 'tm-tag-pop-empty';\n empty.textContent = 'No tags on this board yet';\n listEl.appendChild(empty);\n return;\n }\n const checkedIds = new Set(this._taskTags.map(t => t.id));\n this._boardTags.forEach(tag => {\n const row = document.createElement('button');\n row.type = 'button';\n row.className = 'tm-tag-pop-row';\n row.dataset.tagId = tag.id;\n row.dataset.search = tag.name.toLowerCase();\n if (checkedIds.has(tag.id)) row.dataset.checked = 'true';\n const hex = tag.hex || '#8288A8';\n row.innerHTML =\n '' +\n '' + this.escapeHtml(tag.name) + '' +\n '';\n row.addEventListener('click', (e) => {\n e.stopPropagation();\n const willAdd = row.dataset.checked !== 'true';\n this.toggleTag(tag.id, willAdd);\n if (willAdd) row.dataset.checked = 'true'; else delete row.dataset.checked;\n });\n listEl.appendChild(row);\n });\n };\n renderList();\n\n // Filter + show \"Create\" affordance when query is non-empty and doesn't\n // match an existing tag. Reading from the cached board list keeps the\n // popover responsive without a network round-trip per keystroke.\n search.addEventListener('input', () => {\n const q = search.value.trim().toLowerCase();\n let visible = 0;\n let exact = false;\n listEl.querySelectorAll('.tm-tag-pop-row').forEach(r => {\n const match = !q || r.dataset.search.includes(q);\n r.hidden = !match;\n if (match) visible++;\n if (q && r.dataset.search === q) exact = true;\n });\n if (q && !exact) {\n createWrap.classList.remove('hidden');\n createLabel.textContent = 'Create \"' + search.value.trim() + '\"';\n } else {\n createWrap.classList.add('hidden');\n }\n });\n search.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && !createWrap.classList.contains('hidden')) {\n e.preventDefault();\n createBtn.click();\n }\n if (e.key === 'Escape') { e.preventDefault(); this.closeAddTagPopover(); }\n });\n\n createBtn.addEventListener('click', async (e) => {\n e.stopPropagation();\n const name = search.value.trim();\n if (!name) return;\n try {\n const created = await this.createBoardTag(name);\n if (created) {\n this._boardTags.push(created);\n this._boardTags.sort((a, b) => (a.position || 0) - (b.position || 0));\n this.toggleTag(created.id, true);\n search.value = '';\n createWrap.classList.add('hidden');\n renderList();\n }\n } catch (err) {\n console.error('Tag create failed', err);\n alert('Could not create tag.');\n }\n });\n\n // Position relative to anchor \u2014 clamp to viewport edges.\n const rect = anchor.getBoundingClientRect();\n pop.style.top = (rect.bottom + 6) + 'px';\n pop.style.left = Math.max(8, Math.min(window.innerWidth - 248, rect.left)) + 'px';\n\n setTimeout(() => search.focus(), 30);\n\n const outside = (e) => {\n if (pop.contains(e.target)) return;\n this.closeAddTagPopover();\n };\n setTimeout(() => document.addEventListener('click', outside, true), 0);\n this._activeTagPopover = { element: pop, outside };\n },\n\n closeAddTagPopover() {\n if (!this._activeTagPopover) return;\n document.removeEventListener('click', this._activeTagPopover.outside, true);\n this._activeTagPopover.element.remove();\n this._activeTagPopover = null;\n },\n\n async createBoardTag(name) {\n const response = await fetch('/api/tags/create', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({\n tag: { task_board_id: this.currentBoardId, name: name, color: 'gray' },\n socket_id: window._pusherSocketId || null\n })\n });\n if (!response.ok) throw new Error('Failed to create tag');\n const tag = await response.json();\n // Keep the page-level TagManager cache in sync so the manager modal\n // shows the new tag without a refresh.\n if (window.TagManager && Array.isArray(window.TagManager.tags)) {\n window.TagManager.tags.push(tag);\n window.TagManager.render();\n }\n return tag;\n },\n\n // Add or remove a single tag from the current task. Builds the resulting\n // tag id list and posts it to /api/tasks/set_tags so the server has the\n // canonical \"tags this task has\" each time.\n async toggleTag(tagId, add) {\n const currentIds = new Set(this._taskTags.map(t => t.id));\n if (add) currentIds.add(tagId); else currentIds.delete(tagId);\n const ids = Array.from(currentIds);\n\n try {\n const response = await fetch('/api/tasks/set_tags', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({\n task_id: this.currentTaskId,\n tag_ids: ids,\n socket_id: window._pusherSocketId || null\n })\n });\n if (!response.ok) throw new Error('Failed to update tags');\n const result = await response.json();\n this._taskTags = result.tags || [];\n this.renderTagPills();\n this.flashSaved();\n this.updateCardTagDots(this._taskTags);\n } catch (error) {\n console.error('Error updating tags:', error);\n alert('Could not update tags.');\n }\n },\n\n updateCardTagDots(tags) {\n const taskCard = document.querySelector(`.task-card[data-task-id=\"${this.currentTaskId}\"]`);\n if (!taskCard) return;\n let row = taskCard.querySelector('.task-card-tags');\n if (!tags || !tags.length) {\n if (row) row.remove();\n return;\n }\n if (!row) {\n row = document.createElement('div');\n row.className = 'task-card-tags flex items-center gap-[5px] mb-2 flex-wrap';\n taskCard.insertBefore(row, taskCard.firstChild);\n }\n row.innerHTML = tags.map(t => {\n const hex = t.hex || '#8288A8';\n return '';\n }).join('');\n },\n\n // Pulls the column's color from the .kanban-column dot and writes it to a\n // CSS custom property on the modal shell so the top accent + status badge\n // reflect the lane the task is in.\n applyColumnAccent(columnId, fallbackName) {\n const shell = document.getElementById('task-modal');\n const badge = document.getElementById('task-modal-column-badge');\n if (!shell || !badge) return;\n\n const columnEl = document.querySelector(`.kanban-column[data-column-id=\"${columnId}\"]`);\n const name = (columnEl?.querySelector('.column-name')?.textContent || fallbackName || '\u2014').trim();\n const dotStyle = columnEl?.querySelector('.column-header > span:first-child')?.style.backgroundColor;\n const hex = this.rgbToHex(dotStyle) || '#5B8BFF';\n const c = window.KozColors ? (window.KozColors.byHex(hex) || window.KozColors.byName('blue')) : null;\n\n badge.textContent = name;\n if (c) {\n shell.style.setProperty('--tm-accent', c.hex);\n shell.style.setProperty('--tm-accent-bg', `rgba(${c.rgb},0.13)`);\n shell.style.setProperty('--tm-accent-rim', `rgba(${c.rgb},0.32)`);\n } else {\n shell.style.setProperty('--tm-accent', hex);\n shell.style.setProperty('--tm-accent-bg', hex + '22');\n shell.style.setProperty('--tm-accent-rim', hex + '55');\n }\n },\n\n // Public hook so the column popover can repaint an open modal when the\n // user picks a new color for the column the current task lives in.\n refreshColumnAccent(columnId, _hex) {\n if (!this.currentTaskId) return;\n const card = document.querySelector(`.task-card[data-task-id=\"${this.currentTaskId}\"]`);\n if (!card || String(card.dataset.columnId) !== String(columnId)) return;\n this.applyColumnAccent(columnId, null);\n },\n\n rgbToHex(s) {\n if (!s) return null;\n const m = String(s).match(/rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/);\n if (!m) return null;\n const h = (n) => { const x = parseInt(n, 10).toString(16); return x.length === 1 ? '0' + x : x; };\n return '#' + (h(m[1]) + h(m[2]) + h(m[3])).toUpperCase();\n },\n\n // Snapshot the current board's columns into kdd options (label + accent swatch).\n collectColumnOptions() {\n return Array.from(document.querySelectorAll('.kanban-column')).map(col => {\n const id = col.dataset.columnId;\n const name = (col.querySelector('.column-name')?.textContent || 'Untitled').trim();\n const dot = col.querySelector('.column-header > span:first-child');\n const hex = this.rgbToHex(dot?.style.backgroundColor) || '#5B8BFF';\n return { value: id, label: name, swatch: hex };\n });\n },\n\n buildColumnDropdown(currentColumnId) {\n const host = document.getElementById('task-modal-column-host');\n if (!host) return;\n const options = this.collectColumnOptions();\n\n if (this.kdds.column) {\n this.kdds.column.setOptions(options);\n this.kdds.column.setValue(String(currentColumnId));\n } else {\n host.innerHTML = '';\n this.kdds.column = window.createKdd({\n value: String(currentColumnId),\n options,\n placeholder: 'Select status\u2026',\n onChange: (v) => {\n this.updateTask({ task_column_id: v });\n // Repaint the badge + accent immediately to reflect the new column.\n this.applyColumnAccent(v, null);\n }\n });\n host.appendChild(this.kdds.column.element);\n }\n },\n\n buildMoveBoardDropdown() {\n const host = document.getElementById('task-modal-move-board-host');\n if (!host) return;\n // Note: API for \"other boards\" is not wired in the original module either.\n // We stub with a single placeholder option until that endpoint exists.\n if (this.kdds.moveBoard) return;\n host.innerHTML = '';\n this.kdds.moveBoard = window.createKdd({\n value: '',\n options: [],\n placeholder: 'Select board\u2026',\n onChange: (v) => { if (v) this.moveToBoard(v); }\n });\n host.appendChild(this.kdds.moveBoard.element);\n },\n\n populateAssignees(assignedUsers, members) {\n const container = document.getElementById('task-modal-assignees');\n if (!container) return;\n const assignedIds = assignedUsers.map(u => u.id);\n\n if (!members || members.length === 0) {\n container.innerHTML = '

No workspace members

';\n return;\n }\n\n container.innerHTML = members.map(member => {\n const checked = assignedIds.includes(member.id) ? 'checked' : '';\n const avatar = window.renderAvatar ? window.renderAvatar(member.name, member.image, 6) : '';\n return ``;\n }).join('');\n },\n\n async updateAssignees() {\n const container = document.getElementById('task-modal-assignees');\n const checkedIds = Array.from(container.querySelectorAll('.tm-assignee-checkbox:checked')).map(cb => parseInt(cb.value));\n\n try {\n const response = await fetch('/api/tasks/set_assignees', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({\n task_id: this.currentTaskId,\n user_ids: checkedIds,\n socket_id: window._pusherSocketId || null\n })\n });\n if (!response.ok) throw new Error('Failed to update assignees');\n const result = await response.json();\n this.flashSaved();\n this.updateCardAvatars(result.assigned_users || []);\n } catch (error) {\n console.error('Error updating assignees:', error);\n }\n },\n\n updateCardAvatars(assignedUsers) {\n const taskCard = document.querySelector(`.task-card[data-task-id=\"${this.currentTaskId}\"]`);\n if (!taskCard) return;\n const avatarContainer = taskCard.querySelector('.task-avatars');\n if (!avatarContainer) return;\n avatarContainer.innerHTML = assignedUsers.map(u =>\n window.renderAvatar ? window.renderAvatar(u.name, u.image, 6) : ''\n ).join('');\n },\n\n populateCustomFields(fields, fieldValues) {\n const container = document.getElementById('task-modal-custom-fields');\n if (!container) return;\n container.innerHTML = '';\n this.kdds.fields = {};\n // Cache field metadata for the field-options popover.\n this._fields = fields || [];\n\n if (!fields || fields.length === 0) {\n container.innerHTML = '

No custom properties yet

';\n return;\n }\n\n fields.forEach(field => {\n const value = fieldValues?.[field.id]?.value;\n const row = this.buildFieldRow(field, value);\n container.appendChild(row);\n });\n },\n\n // Builds a single field row (label + input) for the side pane. Selects use\n // kdd; checkbox/text/number/date use styled native inputs. Returns the row\n // element so caller can append.\n buildFieldRow(field, rawValue) {\n const row = document.createElement('div');\n row.className = 'tm-field-row';\n row.dataset.fieldId = field.id;\n\n // Label is a button \u2014 clicking opens the field-options popover so the\n // user can rename, edit choices/colors, or delete.\n const labelBtn = document.createElement('button');\n labelBtn.type = 'button';\n labelBtn.className = 'tm-field-label-btn';\n labelBtn.innerHTML =\n '' + this.escapeHtml(field.name) + '' +\n '';\n labelBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.openFieldOptionsPopover(field, labelBtn);\n });\n row.appendChild(labelBtn);\n\n let value = rawValue;\n // Some serialized values may be JSON-encoded (saveFieldValue stringifies\n // before POSTing). Normalize so we can render consistently.\n if (typeof value === 'string') {\n try { const parsed = JSON.parse(value); if (typeof parsed === 'object' || typeof parsed === 'boolean') value = parsed; } catch(_) {}\n }\n\n const persist = (v) => this.saveFieldValue(field.id, v);\n\n if (field.field_type === 'checkbox') {\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.className = 'tm-field-checkbox';\n cb.checked = (value === true || value === 'true' || value === 1 || value === '1');\n cb.addEventListener('change', () => persist(cb.checked));\n row.appendChild(cb);\n\n } else if (field.field_type === 'select') {\n const opts = this.normalizeChoiceOptions(field.options);\n const kdd = window.createKdd({\n value: value || '',\n options: [{ value: '', label: '\u2014 None \u2014' }].concat(opts),\n placeholder: 'Select\u2026',\n onChange: (v) => persist(v)\n });\n this.kdds.fields[field.id] = kdd;\n row.appendChild(kdd.element);\n\n } else if (field.field_type === 'multi_select') {\n const opts = this.normalizeChoiceOptions(field.options);\n const initial = Array.isArray(value) ? value : (value ? [value] : []);\n const kdd = window.createKddMulti({\n values: initial,\n options: opts,\n placeholder: 'Select\u2026',\n onChange: (v) => persist(v)\n });\n this.kdds.fields[field.id] = kdd;\n row.appendChild(kdd.element);\n\n } else if (field.field_type === 'person') {\n // The API doesn't yet feed the modal a member list per field; reuse the\n // workspace members from the assignees pane via a captured snapshot.\n const opts = this.workspaceMemberOptions();\n const kdd = window.createKdd({\n value: value || '',\n options: [{ value: '', label: '\u2014 None \u2014' }].concat(opts),\n placeholder: 'Select person\u2026',\n onChange: (v) => persist(v)\n });\n this.kdds.fields[field.id] = kdd;\n row.appendChild(kdd.element);\n\n } else if (field.field_type === 'date') {\n const input = document.createElement('input');\n input.type = 'date';\n input.className = 'tm-field-input';\n input.value = value || '';\n input.addEventListener('change', () => persist(input.value));\n row.appendChild(input);\n\n } else if (field.field_type === 'number') {\n const input = document.createElement('input');\n input.type = 'number';\n input.className = 'tm-field-input';\n input.value = value == null ? '' : value;\n input.addEventListener('change', () => persist(input.value));\n row.appendChild(input);\n\n } else if (['url', 'email', 'phone'].includes(field.field_type)) {\n // Link-style fields: render as a clickable chip when filled, with a\n // small edit button next to it. Empty state collapses straight to the\n // editable input so the user can start typing immediately.\n row.appendChild(this._buildLinkField(field, value, persist));\n\n } else if (['created_time', 'last_edited_time'].includes(field.field_type)) {\n // Auto-derived: just show a read-only formatted timestamp.\n const display = document.createElement('div');\n display.className = 'tm-field-readonly';\n display.textContent = this._formatAutoTime(value);\n row.appendChild(display);\n\n } else {\n // text + fallback\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'tm-field-input';\n input.value = value == null ? '' : value;\n input.addEventListener('change', () => persist(input.value));\n row.appendChild(input);\n }\n\n return row;\n },\n\n // Render a URL / email / phone field as a clickable chip when there's a\n // value (with a tiny edit button), or as an open input when empty.\n _buildLinkField(field, value, persist) {\n const wrap = document.createElement('div');\n const renderEditing = (initial) => {\n wrap.innerHTML = '';\n const input = document.createElement('input');\n input.type = field.field_type === 'email' ? 'email'\n : field.field_type === 'phone' ? 'tel'\n : 'url';\n input.className = 'tm-field-input';\n input.placeholder = ({\n url: 'https://example.com',\n email: 'name@example.com',\n phone: '+1 555 0100'\n })[field.field_type] || '';\n input.value = initial || '';\n const commit = () => {\n const v = input.value.trim();\n if (v === (initial || '')) { renderDisplay(initial || ''); return; }\n persist(v);\n renderDisplay(v);\n };\n input.addEventListener('blur', commit);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') { e.preventDefault(); input.blur(); }\n if (e.key === 'Escape') { e.preventDefault(); renderDisplay(initial || ''); }\n });\n wrap.appendChild(input);\n input.focus();\n };\n const renderDisplay = (v) => {\n wrap.innerHTML = '';\n if (!v) {\n // Empty: render the input directly so a single click puts the user\n // straight into editing mode (no extra \"Add\" hover affordance).\n renderEditing('');\n return;\n }\n const editRow = document.createElement('div');\n editRow.className = 'tm-field-edit-row';\n\n const link = document.createElement('a');\n link.className = 'tm-field-link';\n link.href = this._linkHref(field.field_type, v);\n link.target = field.field_type === 'url' ? '_blank' : '_self';\n link.rel = 'noopener noreferrer';\n link.innerHTML =\n '' +\n ({\n url: '',\n email: '',\n phone: ''\n })[field.field_type] +\n '' + this.escapeHtml(v) + '';\n editRow.appendChild(link);\n\n const editBtn = document.createElement('button');\n editBtn.type = 'button';\n editBtn.className = 'tm-field-edit-btn';\n editBtn.title = 'Edit';\n editBtn.innerHTML = '';\n editBtn.addEventListener('click', (e) => { e.stopPropagation(); renderEditing(v); });\n editRow.appendChild(editBtn);\n\n wrap.appendChild(editRow);\n };\n renderDisplay(value || '');\n return wrap;\n },\n\n _linkHref(type, value) {\n const v = String(value).trim();\n if (type === 'email') return 'mailto:' + v;\n if (type === 'phone') return 'tel:' + v.replace(/[^\\d+]/g, '');\n // URL: prepend https:// if no protocol is present.\n return /^https?:\\/\\//i.test(v) ? v : 'https://' + v;\n },\n\n _formatAutoTime(iso) {\n if (!iso) return '\u2014';\n try {\n const d = new Date(iso);\n if (isNaN(d.getTime())) return '\u2014';\n return d.toLocaleString(undefined, {\n month: 'short', day: 'numeric', year: 'numeric',\n hour: 'numeric', minute: '2-digit'\n });\n } catch (_) { return '\u2014'; }\n },\n\n workspaceMemberOptions() {\n return Array.from(document.querySelectorAll('#task-modal-assignees .tm-assignee')).map(label => {\n const cb = label.querySelector('.tm-assignee-checkbox');\n const name = label.querySelector('.tm-assignee-name')?.textContent?.trim();\n return { value: cb?.value, label: name || 'User' };\n }).filter(o => o.value);\n },\n\n // Convert a field's `options` payload (legacy strings or {label,color} objects)\n // into kdd options with colored swatches. The hex is pulled from KozColors so\n // server and client stay aligned on what each color identifier means.\n normalizeChoiceOptions(rawOptions) {\n return (rawOptions || []).map(o => {\n if (o && typeof o === 'object') {\n const c = window.KozColors ? window.KozColors.byName(o.color) : null;\n return { value: o.label, label: o.label, swatch: c ? c.hex : '#8288A8' };\n }\n const c = window.KozColors ? window.KozColors.byName('gray') : null;\n return { value: o, label: o, swatch: c ? c.hex : '#8288A8' };\n });\n },\n\n // \u2500\u2500 Field-options popover \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Opens when the user clicks a field's label. Lets them rename the field,\n // edit options + colors (for select / multi_select), and delete the field.\n // Mirrors the column popover from the data-table page in shape and feel.\n openFieldOptionsPopover(field, anchor) {\n this.closeFieldOptionsPopover();\n\n const isSelect = field.field_type === 'select' || field.field_type === 'multi_select';\n\n const pop = document.createElement('div');\n pop.className = 'tm-field-popover';\n pop.innerHTML =\n '
' + this.escapeHtml(this.fieldTypeLabel(field.field_type)) + ' property
' +\n '
' +\n '
' +\n '' +\n '' +\n '
' +\n (isSelect\n ? '
' +\n '' +\n '
' +\n '
'\n : '') +\n '
' +\n '
' +\n '' +\n '
' +\n '' +\n '' +\n '
' +\n '
';\n\n const nameInput = pop.querySelector('#tm-fp-name');\n nameInput.value = field.name;\n\n let choicesEditor = null;\n if (isSelect) {\n const host = pop.querySelector('#tm-fp-choices-host');\n const countEl = pop.querySelector('#tm-fp-count');\n // Normalize incoming options to {label, color} for the editor.\n const initial = (field.options || []).map(o => (typeof o === 'object' && o)\n ? { label: o.label || '', color: o.color || 'gray' }\n : { label: String(o), color: 'gray' }\n );\n choicesEditor = window.createChoicesEditor({\n initialChoices: initial,\n onChange: (cs) => { countEl.textContent = String(cs.filter(c => c.label).length); }\n });\n host.appendChild(choicesEditor.element);\n }\n\n pop.querySelector('#tm-fp-cancel').addEventListener('click', () => this.closeFieldOptionsPopover());\n pop.querySelector('#tm-fp-save').addEventListener('click', () => {\n const newName = nameInput.value.trim() || field.name;\n const choices = isSelect ? choicesEditor.getChoices().filter(c => c.label) : null;\n this.updateField(field.id, { name: newName, options: choices });\n });\n pop.querySelector('.tm-field-pop-delete').addEventListener('click', () => {\n if (!confirm('Delete this property? Any saved values for it will be lost.')) return;\n this.deleteField(field.id);\n });\n\n // Position relative to the anchor (the field label button).\n const rect = anchor.getBoundingClientRect();\n document.body.appendChild(pop);\n const popRect = pop.getBoundingClientRect();\n let top = rect.bottom + 6;\n if (top + popRect.height > window.innerHeight - 12) top = Math.max(12, rect.top - popRect.height - 6);\n pop.style.top = top + 'px';\n pop.style.left = Math.max(12, Math.min(window.innerWidth - popRect.width - 12, rect.left - 12)) + 'px';\n\n // Outside-click \u2192 close (but ignore clicks inside the color picker, which\n // is portaled to body and would otherwise count as outside).\n const outside = (e) => {\n if (pop.contains(e.target)) return;\n const picker = document.querySelector('.koz-ce-picker');\n if (picker && picker.contains(e.target)) return;\n this.closeFieldOptionsPopover();\n };\n setTimeout(() => document.addEventListener('click', outside, true), 0);\n\n this._activeFieldPopover = { element: pop, outside };\n setTimeout(() => nameInput.focus(), 30);\n },\n\n closeFieldOptionsPopover() {\n if (!this._activeFieldPopover) return;\n document.removeEventListener('click', this._activeFieldPopover.outside, true);\n this._activeFieldPopover.element.remove();\n this._activeFieldPopover = null;\n if (window.closeChoicesColorPicker) window.closeChoicesColorPicker();\n },\n\n fieldTypeLabel(t) {\n const found = (this.fieldTypeCatalog() || []).find(x => x.value === t);\n return found ? found.label : 'Text';\n },\n\n async updateField(fieldId, patch) {\n try {\n const response = await fetch('/api/task_board_fields/update', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({\n task_board_field: Object.assign({ id: fieldId }, patch)\n })\n });\n if (!response.ok) throw new Error('Failed to update field');\n const updated = await response.json();\n\n // Refresh the cached field metadata + the row's UI without re-fetching\n // the whole task. We rebuild only the affected row to preserve other\n // open inputs.\n this._fields = (this._fields || []).map(f => f.id === fieldId ? updated : f);\n this.refreshFieldRow(fieldId);\n this.closeFieldOptionsPopover();\n this.flashSaved();\n } catch (error) {\n console.error('Error updating field:', error);\n alert('Failed to save property changes');\n }\n },\n\n async deleteField(fieldId) {\n try {\n const response = await fetch('/api/task_board_fields/delete', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({ task_board_field: { id: fieldId } })\n });\n if (!response.ok) throw new Error('Failed to delete field');\n\n // Remove the row + drop from cache.\n const row = document.querySelector(`.tm-field-row[data-field-id=\"${fieldId}\"]`);\n if (row) row.remove();\n this._fields = (this._fields || []).filter(f => f.id !== fieldId);\n this.closeFieldOptionsPopover();\n this.flashSaved();\n\n // If no fields remain, restore the empty-state line.\n const container = document.getElementById('task-modal-custom-fields');\n if (container && container.children.length === 0) {\n container.innerHTML = '

No custom properties yet

';\n }\n } catch (error) {\n console.error('Error deleting field:', error);\n alert('Failed to delete property');\n }\n },\n\n // Rebuild a single field row \u2014 preserves the existing value where possible.\n // Used after a field's name or choices change.\n refreshFieldRow(fieldId) {\n const row = document.querySelector(`.tm-field-row[data-field-id=\"${fieldId}\"]`);\n if (!row) return;\n const field = (this._fields || []).find(f => f.id === fieldId);\n if (!field) return;\n\n // Pull the current value from the existing row's controller / inputs.\n let currentValue = null;\n const kdd = this.kdds.fields[field.id];\n if (kdd && typeof kdd.getValue === 'function') currentValue = kdd.getValue();\n else if (kdd && typeof kdd.getValues === 'function') currentValue = kdd.getValues();\n else {\n const input = row.querySelector('input.tm-field-input, input.tm-field-checkbox');\n if (input) currentValue = (input.type === 'checkbox') ? input.checked : input.value;\n }\n\n delete this.kdds.fields[field.id];\n const fresh = this.buildFieldRow(field, currentValue);\n row.replaceWith(fresh);\n },\n\n async loadComments() {\n const container = document.getElementById('task-modal-comments');\n container.innerHTML = '

Loading comments\u2026

';\n\n try {\n const response = await fetch(`/api/task_comments/list/${this.currentTaskId}`);\n if (!response.ok) throw new Error('Failed to load comments');\n const comments = await response.json();\n\n if (comments.length === 0) {\n container.innerHTML = '

No comments yet

';\n return;\n }\n\n container.innerHTML = comments.map(comment => {\n const avatar = window.renderAvatar ? window.renderAvatar(comment.user_name, null, 6) : '';\n return `
\n ${avatar}\n
\n
\n ${this.escapeHtml(comment.user_name)}\n ${this.escapeHtml(comment.created_at_formatted || '')}\n
\n
${this.escapeHtml(comment.content)}
\n
\n
`;\n }).join('');\n } catch (error) {\n console.error('Error loading comments:', error);\n container.innerHTML = '

Failed to load comments

';\n }\n },\n\n async addComment() {\n const input = document.getElementById('task-modal-new-comment');\n const content = input.value.trim();\n if (!content) return;\n try {\n const response = await fetch('/api/task_comments/create', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({\n task_comment: {\n task_id: this.currentTaskId,\n user_id: window.currentUserId,\n content: content\n }\n })\n });\n if (!response.ok) throw new Error('Failed to add comment');\n input.value = '';\n this.loadComments();\n this._bumpCardCommentCount(1);\n } catch (error) {\n console.error('Error adding comment:', error);\n alert('Failed to add comment');\n }\n },\n\n // Bump the comment-count badge on the kanban card by `delta`. The wrapper\n // span is always present in the DOM (just hidden when zero) so we only\n // need to update the number + visibility.\n _bumpCardCommentCount(delta) {\n const card = document.querySelector(`.task-card[data-task-id=\"${this.currentTaskId}\"]`);\n if (!card) return;\n const wrap = card.querySelector('.task-card-comment-count');\n const numEl = card.querySelector('.task-card-comment-count-num');\n if (!wrap || !numEl) return;\n const next = Math.max(0, (parseInt(numEl.textContent, 10) || 0) + delta);\n numEl.textContent = String(next);\n wrap.classList.toggle('hidden', next === 0);\n },\n\n autoSave() {\n if (this.saveTimeout) clearTimeout(this.saveTimeout);\n document.getElementById('task-modal-save-status')?.classList.add('hidden');\n this.saveTimeout = setTimeout(() => {\n const title = document.getElementById('task-modal-title').value;\n const description = document.getElementById('task-modal-description').value;\n this.updateTask({ name: title, description: description });\n }, 500);\n },\n\n flashSaved() {\n const el = document.getElementById('task-modal-save-status');\n if (!el) return;\n el.classList.remove('hidden');\n setTimeout(() => el.classList.add('hidden'), 1800);\n },\n\n async updateTask(data) {\n try {\n const response = await fetch('/api/tasks/update', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({\n task: { id: this.currentTaskId, ...data },\n socket_id: window._pusherSocketId || null\n })\n });\n if (!response.ok) throw new Error('Failed to update task');\n this.flashSaved();\n\n // Mirror the changes onto the kanban card preview so the user doesn't\n // have to refresh to see them. We use stable .task-card-* hooks added\n // in the ERB / buildTaskCard so the lookup is robust.\n const taskCard = document.querySelector(`.task-card[data-task-id=\"${this.currentTaskId}\"]`);\n if (taskCard) {\n if (data.name != null) {\n const titleEl = taskCard.querySelector('.task-card-title');\n if (titleEl) titleEl.textContent = data.name;\n }\n if (data.description != null) {\n this._syncCardDescription(taskCard, data.description);\n }\n }\n if (data.task_column_id) this.moveCardToColumn(data.task_column_id);\n } catch (error) {\n console.error('Error updating task:', error);\n }\n },\n\n // Insert / update / remove the description preview on a task card.\n // Mirrors the server-side rule: truncate to 120 chars, line-clamp to 2.\n // Position: directly after the title, before progress/footer.\n _syncCardDescription(card, descRaw) {\n const desc = (descRaw || '').toString().trim();\n let descEl = card.querySelector('.task-card-desc');\n\n if (!desc) {\n if (descEl) descEl.remove();\n return;\n }\n\n const truncated = desc.length > 120 ? desc.slice(0, 120) : desc;\n if (descEl) {\n descEl.textContent = truncated;\n return;\n }\n\n // No existing description element \u2014 insert one after the title.\n const title = card.querySelector('.task-card-title');\n if (!title) return;\n descEl = document.createElement('div');\n descEl.className = 'task-card-desc text-[12.5px] text-ink-2 leading-[1.5] mb-2.5 line-clamp-2';\n descEl.textContent = truncated;\n title.insertAdjacentElement('afterend', descEl);\n },\n\n moveCardToColumn(columnId) {\n const taskCard = document.querySelector(`.task-card[data-task-id=\"${this.currentTaskId}\"]`);\n const targetContainer = document.querySelector(`.tasks-container[data-column-id=\"${columnId}\"]`);\n if (taskCard && targetContainer) {\n const emptyState = targetContainer.querySelector('.empty-state');\n if (emptyState) emptyState.remove();\n taskCard.dataset.columnId = columnId;\n targetContainer.appendChild(taskCard);\n }\n },\n\n async saveFieldValue(fieldId, value) {\n try {\n const response = await fetch('/api/tasks/save_field_value', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({\n task_id: this.currentTaskId,\n field_id: fieldId,\n value: JSON.stringify(value)\n })\n });\n if (!response.ok) throw new Error('Failed to save field value');\n this.flashSaved();\n } catch (error) {\n console.error('Error saving field value:', error);\n }\n },\n\n async moveToBoard(targetBoardId) {\n try {\n const response = await fetch('/api/tasks/move_to_board', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({ task_id: this.currentTaskId, target_board_id: targetBoardId })\n });\n if (!response.ok) throw new Error('Failed to move task');\n const taskCard = document.querySelector(`.task-card[data-task-id=\"${this.currentTaskId}\"]`);\n if (taskCard) taskCard.remove();\n this.close();\n alert('Task moved to the other board');\n } catch (error) {\n console.error('Error moving task:', error);\n alert('Failed to move task');\n }\n },\n\n async deleteTask() {\n try {\n const response = await fetch('/api/tasks/delete', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({ task: { id: this.currentTaskId }, socket_id: window._pusherSocketId || null })\n });\n if (!response.ok) throw new Error('Failed to delete task');\n const taskCard = document.querySelector(`.task-card[data-task-id=\"${this.currentTaskId}\"]`);\n if (taskCard) taskCard.remove();\n this.close();\n } catch (error) {\n console.error('Error deleting task:', error);\n alert('Failed to delete task');\n }\n },\n\n // \u2500\u2500 Add-property mini modal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n openAddFieldModal() {\n document.getElementById('add-field-modal-overlay').classList.remove('hidden');\n const nameInput = document.getElementById('new-field-name');\n nameInput.value = '';\n delete nameInput.dataset.userTouched;\n // Once the user starts typing, stop suggesting names from the type catalog.\n nameInput.oninput = () => { nameInput.dataset.userTouched = 'true'; };\n\n document.getElementById('new-field-options-container').classList.add('hidden');\n const search = document.getElementById('new-field-type-search');\n if (search) search.value = '';\n this.buildAddFieldTypeDropdown();\n this.buildAddFieldChoicesEditor();\n setTimeout(() => nameInput.focus(), 30);\n },\n\n closeAddFieldModal() {\n document.getElementById('add-field-modal-overlay').classList.add('hidden');\n if (window.closeChoicesColorPicker) window.closeChoicesColorPicker();\n },\n\n // \u2500\u2500 Type picker (Notion-style) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Catalog drives both the Add-property modal's visual list and the\n // friendly labels used elsewhere. Order is intentional \u2014 we lead with the\n // most common types, then group selectors, then link-style types, then\n // auto/system types. Hints are short single-line descriptions.\n fieldTypeCatalog() {\n return [\n { value: 'text', label: 'Text', hint: 'Free-form text', icon: this._typeIconHtml('text') },\n { value: 'number', label: 'Number', hint: 'Numeric value', icon: this._typeIconHtml('number') },\n { value: 'date', label: 'Date', hint: 'A specific day', icon: this._typeIconHtml('date') },\n { value: 'checkbox', label: 'Checkbox', hint: 'Yes / no toggle', icon: this._typeIconHtml('checkbox') },\n { value: 'select', label: 'Select', hint: 'One of a set of colored options', icon: this._typeIconHtml('select') },\n { value: 'multi_select', label: 'Multi-select', hint: 'Many of a set of colored options', icon: this._typeIconHtml('multi_select') },\n { value: 'person', label: 'Person', hint: 'A workspace member', icon: this._typeIconHtml('person') },\n { value: 'url', label: 'URL', hint: 'A clickable link', icon: this._typeIconHtml('url') },\n { value: 'email', label: 'Email', hint: 'An email address (mailto link)', icon: this._typeIconHtml('email') },\n { value: 'phone', label: 'Phone', hint: 'A phone number (tel link)', icon: this._typeIconHtml('phone') },\n { value: 'created_time', label: 'Created time', hint: 'When the task was created', icon: this._typeIconHtml('created_time') },\n { value: 'last_edited_time', label: 'Last edited time', hint: 'When the task was last updated', icon: this._typeIconHtml('last_edited_time') }\n ];\n },\n\n _typeIconHtml(type) {\n // Compact lucide-style SVGs, sized to fit the .tm-type-icon tile.\n const svgs = {\n text: '',\n number: '',\n date: '',\n checkbox: '',\n select: '',\n multi_select: '',\n person: '',\n url: '',\n email: '',\n phone: '',\n created_time: '',\n last_edited_time: ''\n };\n return svgs[type] || svgs.text;\n },\n\n // Builds the Notion-style type picker as a vertical list of clickable rows.\n // Search input filters by label/hint.\n buildAddFieldTypeDropdown() {\n const host = document.getElementById('new-field-type-host');\n if (!host) return;\n host.innerHTML = '';\n this._addFieldType = 'text';\n\n const catalog = this.fieldTypeCatalog();\n const rows = [];\n catalog.forEach(t => {\n const row = document.createElement('button');\n row.type = 'button';\n row.className = 'tm-type-row';\n row.dataset.type = t.value;\n row.dataset.search = (t.label + ' ' + t.hint).toLowerCase();\n row.innerHTML =\n '' + t.icon + '' +\n '' +\n '' + this.escapeHtml(t.label) + '' +\n '' + this.escapeHtml(t.hint) + '' +\n '' +\n '';\n row.addEventListener('click', (e) => {\n e.stopPropagation();\n this._setAddFieldType(t.value);\n });\n host.appendChild(row);\n rows.push(row);\n });\n\n const empty = document.createElement('div');\n empty.className = 'tm-type-empty';\n empty.textContent = 'No matching types';\n empty.hidden = true;\n host.appendChild(empty);\n\n // Search-as-you-type filter \u2014 hides non-matching rows.\n const search = document.getElementById('new-field-type-search');\n if (search) {\n search.value = '';\n search.oninput = () => {\n const q = search.value.trim().toLowerCase();\n let visible = 0;\n rows.forEach(r => {\n const match = !q || r.dataset.search.includes(q);\n r.hidden = !match;\n if (match) visible++;\n });\n empty.hidden = visible > 0;\n };\n }\n\n this._addFieldTypeRows = rows;\n this._setAddFieldType('text');\n },\n\n _setAddFieldType(value) {\n this._addFieldType = value;\n (this._addFieldTypeRows || []).forEach(r => {\n if (r.dataset.type === value) r.dataset.active = 'true';\n else delete r.dataset.active;\n });\n const showOpts = ['select', 'multi_select'].includes(value);\n document.getElementById('new-field-options-container').classList.toggle('hidden', !showOpts);\n\n // If the user hasn't typed a name, suggest one based on the type.\n const nameInput = document.getElementById('new-field-name');\n if (nameInput && !nameInput.dataset.userTouched) {\n const pretty = (this.fieldTypeCatalog().find(t => t.value === value) || {}).label || '';\n nameInput.value = pretty;\n }\n },\n\n buildAddFieldChoicesEditor() {\n const host = document.getElementById('new-field-options-host');\n if (!host) return;\n host.innerHTML = '';\n const countEl = document.getElementById('new-field-options-count');\n this._addFieldChoicesEditor = window.createChoicesEditor({\n initialChoices: [],\n onChange: (cs) => {\n if (countEl) countEl.textContent = String(cs.filter(c => c.label).length);\n }\n });\n host.appendChild(this._addFieldChoicesEditor.element);\n if (countEl) countEl.textContent = '0';\n },\n\n async addField() {\n const name = document.getElementById('new-field-name').value.trim();\n const fieldType = this._addFieldType || 'text';\n\n if (!name) { alert('Please enter a property name'); return; }\n\n const isSelect = ['select', 'multi_select'].includes(fieldType);\n const options = isSelect && this._addFieldChoicesEditor\n ? this._addFieldChoicesEditor.getChoices().filter(c => c.label)\n : [];\n\n try {\n const response = await fetch('/api/task_board_fields/create', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfToken },\n body: JSON.stringify({\n task_board_field: {\n task_board_id: this.currentBoardId,\n name, field_type: fieldType, options\n }\n })\n });\n if (!response.ok) throw new Error('Failed to create field');\n const field = await response.json();\n\n const container = document.getElementById('task-modal-custom-fields');\n const empty = container.querySelector('.tm-empty-line');\n if (empty) empty.remove();\n container.appendChild(this.buildFieldRow(field, null));\n this._fields = (this._fields || []).concat([field]);\n this.closeAddFieldModal();\n } catch (error) {\n console.error('Error creating field:', error);\n alert('Failed to create property');\n }\n },\n\n escapeHtml(text) {\n const div = document.createElement('div');\n div.textContent = text == null ? '' : String(text);\n return div.innerHTML;\n }\n};\n\ndocument.addEventListener('DOMContentLoaded', () => { TaskModal.init(); });\nwindow.TaskModal = TaskModal;\n", "// Block Editor Module - Notion-style content editing\nconst BlockEditor = {\n container: null,\n blocksContainer: null,\n titleInput: null,\n pageId: null,\n saveUrl: null,\n csrfToken: null,\n saveTimeout: null,\n currentSlashQuery: '',\n slashStartPos: null,\n draggedBlock: null,\n dropIndicator: null,\n selectionToolbar: null,\n blockActionsMenu: null,\n currentActionsBlock: null,\n\n // Block types that support inline rich-text formatting (innerHTML-based content).\n // `code` is intentionally excluded \u2014 it's preformatted plaintext.\n RICH_TEXT_TYPES: ['text', 'heading1', 'heading2', 'heading3', 'bullet', 'numbered', 'todo', 'quote', 'callout'],\n\n // Block types whose content is a single uploaded asset or external URL,\n // serialized as a `@ {json}` sentinel line and rendered from a\n // dataset.meta blob rather than .block-content.\n MEDIA_TYPES: ['image', 'video', 'audio', 'file', 'bookmark'],\n\n // Notion-style text color palette. `null` value means \"remove color\".\n TEXT_COLORS: [\n { key: 'default', label: 'Default', hex: null },\n { key: 'gray', label: 'Gray', hex: '#9ca3af' },\n { key: 'brown', label: 'Brown', hex: '#a98467' },\n { key: 'orange', label: 'Orange', hex: '#f59e0b' },\n { key: 'yellow', label: 'Yellow', hex: '#eab308' },\n { key: 'green', label: 'Green', hex: '#22c55e' },\n { key: 'blue', label: 'Blue', hex: '#3b82f6' },\n { key: 'purple', label: 'Purple', hex: '#a855f7' },\n { key: 'pink', label: 'Pink', hex: '#ec4899' },\n { key: 'red', label: 'Red', hex: '#ef4444' },\n ],\n\n blockTypes: [\n { type: 'text', label: 'Text', icon: 'type', shortcut: '', description: 'Plain text paragraph' },\n { type: 'heading1', label: 'Heading 1', icon: null, iconText: 'H1', shortcut: '#', description: 'Large heading' },\n { type: 'heading2', label: 'Heading 2', icon: null, iconText: 'H2', shortcut: '##', description: 'Medium heading' },\n { type: 'heading3', label: 'Heading 3', icon: null, iconText: 'H3', shortcut: '###', description: 'Small heading' },\n { type: 'bullet', label: 'Bulleted list', icon: 'list', shortcut: '-', description: 'Unordered list item' },\n { type: 'numbered', label: 'Numbered list', icon: 'list-ordered', shortcut: '1.', description: 'Ordered list item' },\n { type: 'todo', label: 'To-do list', icon: 'square-check', shortcut: '[]', description: 'Checkbox item' },\n { type: 'quote', label: 'Quote', icon: 'quote', shortcut: '>', description: 'Blockquote' },\n { type: 'divider', label: 'Divider', icon: 'minus', shortcut: '---', description: 'Horizontal line' },\n { type: 'callout', label: 'Callout', icon: 'alert-circle', shortcut: '', description: 'Highlighted note' },\n { type: 'code', label: 'Code', icon: 'code', shortcut: '```', description: 'Code block' },\n { type: 'image', label: 'Image', icon: 'image', shortcut: '', description: 'Upload or embed an image' },\n { type: 'video', label: 'Video', icon: 'video', shortcut: '', description: 'Upload a video file' },\n { type: 'audio', label: 'Audio', icon: 'volume-2', shortcut: '', description: 'Upload an audio clip' },\n { type: 'file', label: 'File', icon: 'paperclip', shortcut: '', description: 'Attach any file' },\n { type: 'bookmark', label: 'Web bookmark', icon: 'bookmark', shortcut: '', description: 'Save a link as a card' },\n ],\n\n init() {\n this.container = document.getElementById('block-editor');\n if (!this.container) return;\n\n this.blocksContainer = document.getElementById('page-blocks');\n this.titleInput = document.getElementById('page-title-input');\n this.pageId = this.container.dataset.pageId;\n this.pageUuid = this.container.dataset.pageUuid;\n this.projectId = this.container.dataset.projectId;\n this.saveUrl = this.container.dataset.saveUrl;\n this.createUrl = this.container.dataset.createUrl || '/pages';\n this.uploadMediaUrl = this.container.dataset.uploadMediaUrl;\n\n // Get CSRF token - prefer data attribute, fallback to meta tag\n this.csrfToken = this.container.dataset.csrfToken\n || document.querySelector('meta[name=\"csrf-token\"]')?.getAttribute('content')\n || document.querySelector('input[name=\"authenticity_token\"]')?.value;\n\n // Parse initial content\n const content = this.blocksContainer?.dataset.content || '';\n this.renderBlocks(this.parseMarkdownToBlocks(content));\n\n this.bindEvents();\n },\n\n parseMarkdownToBlocks(md) {\n if (!md || !md.trim()) {\n return [{ type: 'text', content: '', id: this.generateId() }];\n }\n\n const lines = md.split('\\n');\n const blocks = [];\n let inCodeBlock = false;\n let codeContent = [];\n let codeLanguage = '';\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Code block handling\n if (line.startsWith('```')) {\n if (inCodeBlock) {\n blocks.push({ type: 'code', content: codeContent.join('\\n'), language: codeLanguage, id: this.generateId() });\n codeContent = [];\n codeLanguage = '';\n inCodeBlock = false;\n } else {\n inCodeBlock = true;\n codeLanguage = line.slice(3).trim();\n }\n continue;\n }\n\n if (inCodeBlock) {\n codeContent.push(line);\n continue;\n }\n\n // Page link sentinel \u2014 `@page {\"url\":\"...\",\"icon\":\"...\",\"title\":\"...\",\"uuid\":\"...\"}`\n if (line.startsWith('@page ')) {\n try {\n const meta = JSON.parse(line.slice(6));\n if (meta && meta.url) {\n blocks.push({\n type: 'page_link',\n content: '',\n meta: meta,\n id: this.generateId()\n });\n continue;\n }\n } catch (err) { /* fall through to plain text */ }\n }\n\n // Media sentinels \u2014 `@image {json}`, `@video {json}`, etc.\n // Each carries a `meta` blob with at least `url`. Image/video/audio also\n // support `caption`; file has `name`/`size`; bookmark has `title`/`description`.\n let mediaHandled = false;\n for (const sentinel of this.MEDIA_TYPES) {\n const prefix = '@' + sentinel + ' ';\n if (line.startsWith(prefix)) {\n try {\n const meta = JSON.parse(line.slice(prefix.length));\n if (meta && meta.url) {\n blocks.push({ type: sentinel, content: '', meta: meta, id: this.generateId() });\n mediaHandled = true;\n break;\n }\n } catch (err) { /* fall through */ }\n }\n }\n if (mediaHandled) continue;\n\n // Divider\n if (line.match(/^-{3,}$/) || line.match(/^\\*{3,}$/) || line.match(/^_{3,}$/)) {\n blocks.push({ type: 'divider', content: '', id: this.generateId() });\n continue;\n }\n\n // Headings\n if (line.startsWith('### ')) {\n blocks.push({ type: 'heading3', content: line.slice(4), id: this.generateId() });\n continue;\n }\n if (line.startsWith('## ')) {\n blocks.push({ type: 'heading2', content: line.slice(3), id: this.generateId() });\n continue;\n }\n if (line.startsWith('# ')) {\n blocks.push({ type: 'heading1', content: line.slice(2), id: this.generateId() });\n continue;\n }\n\n // To-do items\n if (line.match(/^- \\[[ x]\\] /i)) {\n const checked = line.match(/^- \\[x\\] /i);\n // Keep
and any inline formatting tags intact \u2014 rendered via innerHTML.\n const todoContent = line.slice(6);\n blocks.push({ type: 'todo', content: todoContent, checked: !!checked, id: this.generateId() });\n continue;\n }\n\n // Bullet lists\n if (line.match(/^[-*+] /)) {\n blocks.push({ type: 'bullet', content: line.slice(2), id: this.generateId() });\n continue;\n }\n\n // Numbered lists\n if (line.match(/^\\d+\\. /)) {\n const match = line.match(/^(\\d+)\\. (.*)$/);\n if (match) {\n blocks.push({ type: 'numbered', content: match[2], number: parseInt(match[1]), id: this.generateId() });\n }\n continue;\n }\n\n // Callout (distinct marker so it roundtrips regardless of content)\n if (line.startsWith('>! ')) {\n blocks.push({ type: 'callout', content: line.slice(3), id: this.generateId() });\n continue;\n }\n\n // Quote\n if (line.startsWith('> ')) {\n blocks.push({ type: 'quote', content: line.slice(2), id: this.generateId() });\n continue;\n }\n\n // Blank line \u2192 preserve as an empty text block so spacing roundtrips.\n if (line.trim() === '') {\n blocks.push({ type: 'text', content: '', id: this.generateId() });\n continue;\n }\n\n blocks.push({ type: 'text', content: line, id: this.generateId() });\n }\n\n // Ensure at least one empty block\n if (blocks.length === 0) {\n blocks.push({ type: 'text', content: '', id: this.generateId() });\n }\n\n return blocks;\n },\n\n blocksToMarkdown() {\n const blockEls = this.blocksContainer.querySelectorAll('.block-line');\n const lines = [];\n\n // Helper: serialize a block's editable content, preserving inline formatting\n // for rich types (innerHTML, sanitized) and falling back to plain text for\n // code blocks. Returns a single line \u2014 newlines are encoded as
.\n const serializeContent = (contentEl, type) => {\n if (!contentEl) return '';\n if (type === 'code') return contentEl.textContent || '';\n const html = this.sanitizeRich(contentEl.innerHTML || '');\n // Any literal newlines from a
/
child shouldn't sneak into a single markdown line.\n return html.replace(/\\r?\\n/g, '');\n };\n\n blockEls.forEach(blockEl => {\n const type = blockEl.dataset.blockType;\n const contentEl = blockEl.querySelector('.block-content');\n const content = serializeContent(contentEl, type);\n\n switch (type) {\n case 'heading1':\n lines.push(`# ${content}`);\n break;\n case 'heading2':\n lines.push(`## ${content}`);\n break;\n case 'heading3':\n lines.push(`### ${content}`);\n break;\n case 'bullet':\n lines.push(`- ${content}`);\n break;\n case 'numbered':\n const num = blockEl.dataset.number || '1';\n lines.push(`${num}. ${content}`);\n break;\n case 'todo':\n const checked = blockEl.querySelector('input[type=\"checkbox\"]')?.checked;\n lines.push(`- [${checked ? 'x' : ' '}] ${content}`);\n break;\n case 'quote':\n lines.push(`> ${content}`);\n break;\n case 'callout':\n lines.push(`>! ${content}`);\n break;\n case 'divider':\n lines.push('---');\n break;\n case 'code':\n const lang = blockEl.dataset.language || '';\n lines.push('```' + lang);\n lines.push(content);\n lines.push('```');\n break;\n case 'page_link':\n if (blockEl.dataset.meta) {\n lines.push('@page ' + blockEl.dataset.meta);\n }\n break;\n case 'image':\n case 'video':\n case 'audio':\n case 'file':\n case 'bookmark': {\n if (!blockEl.dataset.meta) break;\n let meta = {};\n try { meta = JSON.parse(blockEl.dataset.meta); } catch (_) { meta = {}; }\n // Pull the latest user-edited caption back into meta before serialize.\n const cap = blockEl.querySelector('.block-caption');\n if (cap) meta.caption = cap.textContent || '';\n if (meta.url) lines.push('@' + type + ' ' + JSON.stringify(meta));\n break;\n }\n default:\n // Preserve empty text blocks as blank lines so user-inserted spacing\n // survives a save/reload cycle.\n lines.push(content);\n }\n });\n\n return lines.join('\\n');\n },\n\n renderBlocks(blocks) {\n this.blocksContainer.innerHTML = '';\n\n blocks.forEach((block, index) => {\n const blockEl = this.createBlockElement(block, index);\n this.blocksContainer.appendChild(blockEl);\n });\n\n // Ensure there's always at least one block\n if (blocks.length === 0 || this.blocksContainer.children.length === 0) {\n const emptyBlock = this.createBlockElement({ type: 'text', content: '', id: this.generateId() }, 0);\n this.blocksContainer.appendChild(emptyBlock);\n }\n\n this.updateNumberedLists();\n\n // Re-init lucide icons\n if (typeof lucide !== 'undefined') {\n lucide.createIcons();\n }\n },\n\n createBlockElement(block, index) {\n const div = document.createElement('div');\n div.className = 'block-line flex items-start py-1';\n div.dataset.blockId = block.id;\n div.dataset.blockType = block.type;\n\n if (block.type === 'numbered') {\n div.dataset.number = block.number || (index + 1);\n }\n\n if (block.type === 'code') {\n div.dataset.language = block.language || '';\n }\n\n // Add block button (shows on hover - visibility controlled by CSS)\n const addBtn = document.createElement('button');\n addBtn.className = 'add-block-btn p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded mr-1 flex-shrink-0';\n addBtn.innerHTML = '';\n addBtn.addEventListener('click', (e) => {\n e.preventDefault();\n this.showBlockMenu(addBtn, div);\n });\n\n // Drag handle: drag to reorder, click to open the block actions menu.\n const dragHandle = document.createElement('button');\n dragHandle.type = 'button';\n dragHandle.className = 'drag-handle p-1 text-gray-400 hover:text-gray-600 cursor-grab mr-1 flex-shrink-0';\n dragHandle.innerHTML = '';\n dragHandle.draggable = true;\n dragHandle.title = 'Click for actions, drag to reorder';\n\n // Distinguish click from drag: track mousedown position; if pointer barely\n // moves between mousedown and mouseup, treat as click (and skip drag).\n let mouseDownAt = null;\n dragHandle.addEventListener('mousedown', (e) => {\n mouseDownAt = { x: e.clientX, y: e.clientY };\n div.draggable = true;\n });\n dragHandle.addEventListener('mouseup', () => {\n div.draggable = false;\n });\n\n dragHandle.addEventListener('click', (e) => {\n // Suppress click that follows a drag (browsers fire click after dragend).\n if (mouseDownAt) {\n const dx = Math.abs((e.clientX || 0) - mouseDownAt.x);\n const dy = Math.abs((e.clientY || 0) - mouseDownAt.y);\n mouseDownAt = null;\n if (dx > 4 || dy > 4) return;\n }\n e.preventDefault();\n e.stopPropagation();\n this.showBlockActionsMenu(dragHandle, div);\n });\n\n div.addEventListener('dragstart', (e) => this.handleDragStart(e, div));\n div.addEventListener('dragend', (e) => this.handleDragEnd(e, div));\n div.addEventListener('dragover', (e) => this.handleDragOver(e, div));\n div.addEventListener('dragleave', (e) => this.handleDragLeave(e, div));\n div.addEventListener('drop', (e) => this.handleDrop(e, div));\n\n div.appendChild(addBtn);\n div.appendChild(dragHandle);\n\n // Content area based on block type\n if (block.type === 'divider') {\n const hr = document.createElement('div');\n hr.className = 'flex-1 border-t border-gray-300 my-3';\n div.appendChild(hr);\n } else if (this.MEDIA_TYPES.includes(block.type)) {\n this.renderMediaBlock(div, block);\n } else if (block.type === 'page_link') {\n const meta = block.meta || {};\n // Persist the meta on the element so blocksToMarkdown can re-emit it.\n div.dataset.meta = JSON.stringify(meta);\n\n const link = document.createElement('a');\n link.href = meta.url || '#';\n link.className = 'flex items-center gap-2.5 flex-1 px-2 py-1.5 rounded-md text-ink-1 hover:bg-white/[0.04] transition-colors no-underline group/page';\n link.innerHTML =\n '' +\n (meta.icon || '\uD83D\uDCC4') +\n '' +\n '' +\n (meta.title ? this.escapeHtml(meta.title) : 'Untitled') +\n '' +\n '';\n div.appendChild(link);\n } else if (block.type === 'todo') {\n const wrapper = document.createElement('div');\n wrapper.className = 'flex items-start flex-1';\n\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.checked = block.checked || false;\n checkbox.className = 'mt-1 mr-2 w-4 h-4 text-kozado-500 rounded border-gray-300 focus:ring-kozado-500';\n checkbox.addEventListener('change', () => this.scheduleAutoSave());\n\n const content = document.createElement('div');\n content.className = `block-content flex-1 outline-none ${block.checked ? 'line-through text-gray-400' : ''}`;\n content.contentEditable = true;\n content.innerHTML = this.sanitizeRich(block.content || '');\n content.dataset.placeholder = 'To-do item...';\n\n wrapper.appendChild(checkbox);\n wrapper.appendChild(content);\n div.appendChild(wrapper);\n } else {\n const content = document.createElement('div');\n content.className = 'block-content flex-1 outline-none ' + this.getBlockClass(block.type);\n content.contentEditable = true;\n // Code blocks are plaintext only \u2014 keep textContent so any inline tags render literally.\n if (block.type === 'code') {\n content.textContent = block.content || '';\n } else {\n content.innerHTML = this.sanitizeRich(block.content || '');\n }\n content.dataset.placeholder = this.getPlaceholder(block.type);\n\n if (block.type === 'callout') {\n const wrapper = document.createElement('div');\n wrapper.className = 'flex-1 bg-amber-50 border-l-4 border-amber-400 p-3 rounded-r text-gray-900';\n wrapper.appendChild(content);\n div.appendChild(wrapper);\n } else if (block.type === 'code') {\n content.className = 'block-content flex-1 outline-none font-mono text-sm bg-gray-100 p-3 rounded whitespace-pre-wrap';\n div.appendChild(content);\n } else {\n div.appendChild(content);\n }\n }\n\n return div;\n },\n\n getBlockClass(type) {\n const classes = {\n heading1: 'text-3xl font-bold text-ink-0',\n heading2: 'text-2xl font-semibold text-ink-0',\n heading3: 'text-xl font-semibold text-ink-0',\n quote: 'italic',\n bullet: 'ml-4',\n numbered: 'ml-4',\n code: 'font-mono text-sm',\n };\n return classes[type] || '';\n },\n\n getPlaceholder(type) {\n const placeholders = {\n text: \"Type '/' for commands...\",\n heading1: 'Heading 1',\n heading2: 'Heading 2',\n heading3: 'Heading 3',\n bullet: 'List item',\n numbered: 'List item',\n quote: 'Quote',\n callout: 'Callout text...',\n code: 'Code...',\n };\n return placeholders[type] || \"Type '/' for commands...\";\n },\n\n bindEvents() {\n // Title input auto-save\n this.titleInput?.addEventListener('input', () => this.scheduleAutoSave());\n\n // Block content events\n this.blocksContainer.addEventListener('input', (e) => {\n if (e.target.classList.contains('block-content')) {\n this.handleInput(e);\n }\n });\n\n this.blocksContainer.addEventListener('keydown', (e) => {\n if (e.target.classList.contains('block-content')) {\n this.handleKeydown(e);\n }\n });\n\n // Block menu item clicks\n document.addEventListener('click', (e) => {\n const menuItem = e.target.closest('.block-menu-item');\n if (menuItem) {\n const type = menuItem.dataset.blockType;\n this.insertBlockType(type);\n this.hideBlockMenu();\n }\n });\n\n // Close menu on outside click\n document.addEventListener('click', (e) => {\n const menu = document.getElementById('block-menu');\n if (menu && !menu.contains(e.target) && !e.target.closest('.add-block-btn')) {\n this.hideBlockMenu();\n }\n // Close block actions menu on outside click\n if (this.blockActionsMenu && !this.blockActionsMenu.classList.contains('hidden')) {\n if (!this.blockActionsMenu.contains(e.target) && !e.target.closest('.drag-handle')) {\n this.hideBlockActionsMenu();\n }\n }\n });\n\n // Block menu filter\n const filterInput = document.getElementById('block-menu-filter');\n filterInput?.addEventListener('input', (e) => {\n this.filterBlockMenu(e.target.value);\n });\n\n // ESC to close menus\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n this.hideBlockMenu();\n this.hideBlockActionsMenu();\n }\n });\n\n // Selection-based formatting toolbar\n this.buildSelectionToolbar();\n document.addEventListener('selectionchange', () => this.updateSelectionToolbar());\n window.addEventListener('scroll', () => this.repositionSelectionToolbar(), true);\n window.addEventListener('resize', () => this.repositionSelectionToolbar());\n\n // Build the block actions menu lazily on first open\n },\n\n handleInput(e) {\n const content = e.target.textContent;\n const blockType = e.target.closest('.block-line')?.dataset.blockType;\n\n // Detect \"/\" command \u2014 but never inside code blocks, where \"/\" is a literal character\n if (blockType !== 'code' && content.includes('/')) {\n const slashIndex = content.lastIndexOf('/');\n const query = content.slice(slashIndex + 1);\n\n if (slashIndex === content.length - 1 || query.length < 15) {\n this.currentSlashQuery = query;\n this.slashStartPos = slashIndex;\n this.showBlockMenuAtCursor(e.target);\n this.filterBlockMenu(query);\n return;\n }\n }\n\n this.hideBlockMenu();\n this.scheduleAutoSave();\n },\n\n handleKeydown(e) {\n const blockLine = e.target.closest('.block-line');\n const menu = document.getElementById('block-menu');\n const isMenuVisible = menu && !menu.classList.contains('hidden');\n\n // Handle menu navigation when visible\n if (isMenuVisible) {\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n e.preventDefault();\n this.navigateMenu(e.key === 'ArrowDown' ? 1 : -1);\n return;\n }\n if (e.key === 'Enter') {\n e.preventDefault();\n const selected = menu.querySelector('.block-menu-item.bg-gray-100');\n if (selected) {\n const type = selected.dataset.blockType;\n // Remove the slash command text\n const content = e.target.textContent;\n e.target.textContent = content.slice(0, this.slashStartPos);\n this.insertBlockType(type);\n }\n this.hideBlockMenu();\n return;\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n this.hideBlockMenu();\n return;\n }\n }\n\n // Enter - create new block\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n const blockType = blockLine.dataset.blockType;\n const isEmpty = e.target.textContent.trim() === '';\n\n // List-style blocks: Enter continues the list; Enter on an empty\n // item exits the list as a plain text block.\n if (blockType === 'todo' || blockType === 'bullet' || blockType === 'numbered') {\n if (isEmpty) {\n const newBlock = this.createBlockElement({\n type: 'text',\n content: '',\n id: this.generateId()\n }, 0);\n blockLine.replaceWith(newBlock);\n const newContent = newBlock.querySelector('.block-content');\n newContent?.focus();\n if (typeof lucide !== 'undefined') lucide.createIcons();\n this.updateNumberedLists();\n this.scheduleAutoSave();\n return;\n }\n this.insertBlockAfter(blockLine, blockType);\n return;\n }\n\n this.insertBlockAfter(blockLine, 'text');\n return;\n }\n\n // ArrowUp / ArrowDown \u2014 move the caret across blocks. Default browser\n // behavior keeps the caret inside the contentEditable, which feels broken\n // when each block is its own editor. We only intercept when the caret is\n // on the first/last visual line, so wrapped paragraphs still navigate\n // line-by-line internally.\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n const target = e.target;\n const goingUp = e.key === 'ArrowUp';\n if (this.isCaretAtEdgeLine(target, goingUp)) {\n const sibling = goingUp\n ? this.findPrevEditableBlock(blockLine)\n : this.findNextEditableBlock(blockLine);\n if (sibling) {\n e.preventDefault();\n this.focusBlockContent(sibling, goingUp ? 'end' : 'start');\n return;\n }\n }\n }\n\n // Backspace on empty block - delete and move to previous\n if (e.key === 'Backspace' && e.target.textContent === '') {\n const prevBlock = blockLine.previousElementSibling;\n if (prevBlock && this.blocksContainer.children.length > 1) {\n e.preventDefault();\n blockLine.remove();\n const prevContent = prevBlock.querySelector('.block-content');\n if (prevContent) {\n prevContent.focus();\n // Move cursor to end\n const range = document.createRange();\n range.selectNodeContents(prevContent);\n range.collapse(false);\n const sel = window.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n }\n this.scheduleAutoSave();\n }\n return;\n }\n\n // Tab - indent (for lists)\n if (e.key === 'Tab') {\n e.preventDefault();\n // Could implement indentation for lists here\n return;\n }\n },\n\n navigateMenu(direction) {\n const menu = document.getElementById('block-menu');\n const items = Array.from(menu.querySelectorAll('.block-menu-item:not(.hidden)'));\n if (items.length === 0) return;\n\n const current = menu.querySelector('.block-menu-item.bg-gray-100');\n let currentIndex = items.indexOf(current);\n\n if (current) {\n current.classList.remove('bg-gray-100');\n }\n\n currentIndex += direction;\n if (currentIndex < 0) currentIndex = items.length - 1;\n if (currentIndex >= items.length) currentIndex = 0;\n\n items[currentIndex].classList.add('bg-gray-100');\n items[currentIndex].scrollIntoView({ block: 'nearest' });\n },\n\n // Position the slash menu next to the supplied anchor rect, flipping above\n // when there's not enough room below the rect, and clamping into the\n // viewport horizontally. Must be called *after* the menu is unhidden so\n // offsetWidth/offsetHeight are accurate.\n positionBlockMenu(anchorRect) {\n const menu = document.getElementById('block-menu');\n if (!menu) return;\n const margin = 8;\n const w = menu.offsetWidth;\n const h = menu.offsetHeight;\n\n let left = anchorRect.left;\n if (left + w + margin > window.innerWidth) left = Math.max(margin, window.innerWidth - w - margin);\n if (left < margin) left = margin;\n\n // Prefer below; flip above if the menu would overflow the viewport bottom\n // and there's more room above the anchor.\n const spaceBelow = window.innerHeight - anchorRect.bottom - margin;\n const spaceAbove = anchorRect.top - margin;\n let top;\n if (spaceBelow >= h || spaceBelow >= spaceAbove) {\n top = Math.min(anchorRect.bottom + 4, window.innerHeight - h - margin);\n top = Math.max(margin, top);\n } else {\n top = Math.max(margin, anchorRect.top - h - 4);\n }\n\n menu.style.left = `${left}px`;\n menu.style.top = `${top}px`;\n },\n\n showBlockMenu(anchorEl, blockLine) {\n const menu = document.getElementById('block-menu');\n if (!menu) return;\n\n this.currentBlockLine = blockLine;\n\n menu.classList.remove('hidden');\n this.positionBlockMenu(anchorEl.getBoundingClientRect());\n\n // Reset filter\n const filterInput = document.getElementById('block-menu-filter');\n if (filterInput) {\n filterInput.value = '';\n filterInput.focus();\n }\n this.filterBlockMenu('');\n\n // Select first item\n const firstItem = menu.querySelector('.block-menu-item');\n if (firstItem) {\n menu.querySelectorAll('.block-menu-item').forEach(el => el.classList.remove('bg-gray-100'));\n firstItem.classList.add('bg-gray-100');\n }\n },\n\n showBlockMenuAtCursor(contentEl) {\n const menu = document.getElementById('block-menu');\n if (!menu) return;\n\n this.currentBlockLine = contentEl.closest('.block-line');\n\n menu.classList.remove('hidden');\n\n // Anchor on the caret rect when available, else the block-content element.\n const sel = window.getSelection();\n let anchorRect;\n if (sel.rangeCount > 0) {\n anchorRect = sel.getRangeAt(0).getBoundingClientRect();\n if (anchorRect.width === 0 && anchorRect.height === 0) {\n anchorRect = contentEl.getBoundingClientRect();\n }\n } else {\n anchorRect = contentEl.getBoundingClientRect();\n }\n this.positionBlockMenu(anchorRect);\n\n // Select first item\n const firstItem = menu.querySelector('.block-menu-item:not(.hidden)');\n if (firstItem) {\n menu.querySelectorAll('.block-menu-item').forEach(el => el.classList.remove('bg-gray-100'));\n firstItem.classList.add('bg-gray-100');\n }\n },\n\n hideBlockMenu() {\n const menu = document.getElementById('block-menu');\n if (menu) {\n menu.classList.add('hidden');\n }\n this.currentSlashQuery = '';\n this.slashStartPos = null;\n },\n\n filterBlockMenu(query) {\n const menu = document.getElementById('block-menu');\n if (!menu) return;\n\n const items = menu.querySelectorAll('.block-menu-item');\n const lowerQuery = query.toLowerCase();\n\n let firstVisible = null;\n items.forEach(item => {\n const label = item.querySelector('span')?.textContent.toLowerCase() || '';\n const type = item.dataset.blockType.toLowerCase();\n const matches = label.includes(lowerQuery) || type.includes(lowerQuery);\n item.classList.toggle('hidden', !matches);\n item.classList.remove('bg-gray-100');\n if (matches && !firstVisible) {\n firstVisible = item;\n }\n });\n\n if (firstVisible) {\n firstVisible.classList.add('bg-gray-100');\n }\n },\n\n insertBlockType(type) {\n if (!this.currentBlockLine) return;\n\n // Sub-page: create a child page server-side, then insert a page_link block.\n if (type === 'subpage') {\n this.insertSubpageBlock(this.currentBlockLine);\n return;\n }\n\n // Media types: trigger an asynchronous flow (file picker or URL prompt)\n // rather than a same-line type conversion.\n if (this.MEDIA_TYPES.includes(type)) {\n this.insertMediaBlock(this.currentBlockLine, type);\n return;\n }\n\n // Convert current block to the new type\n const content = this.currentBlockLine.querySelector('.block-content');\n const currentContent = content?.textContent || '';\n\n // Remove slash command from content\n let cleanContent = currentContent;\n if (this.slashStartPos !== null) {\n cleanContent = currentContent.slice(0, this.slashStartPos);\n }\n\n const newBlock = this.createBlockElement({\n type: type,\n content: cleanContent,\n id: this.generateId()\n }, 0);\n\n this.currentBlockLine.replaceWith(newBlock);\n\n this.updateNumberedLists();\n\n // Focus the new block's content\n const newContent = newBlock.querySelector('.block-content');\n if (newContent) {\n newContent.focus();\n // Move cursor to end\n const range = document.createRange();\n range.selectNodeContents(newContent);\n range.collapse(false);\n const sel = window.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n }\n\n // Re-init icons\n if (typeof lucide !== 'undefined') {\n lucide.createIcons();\n }\n\n this.scheduleAutoSave();\n },\n\n async insertSubpageBlock(blockLine) {\n // Strip the slash query from the source block first.\n const content = blockLine.querySelector('.block-content');\n if (content && this.slashStartPos !== null) {\n content.textContent = (content.textContent || '').slice(0, this.slashStartPos);\n }\n\n // Insert a temporary \"creating\u2026\" placeholder right after the source block.\n const placeholder = document.createElement('div');\n placeholder.className = 'flex items-center gap-2 px-2 py-1.5 text-[13px] text-ink-3 italic';\n placeholder.innerHTML = ' Creating sub-page\u2026';\n blockLine.after(placeholder);\n if (typeof lucide !== 'undefined') lucide.createIcons();\n\n try {\n const body = { page: { parent_id: this.pageId, title: 'Untitled' } };\n if (this.projectId) body.page.project_id = this.projectId;\n\n const res = await fetch(this.createUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n 'X-CSRF-Token': this.csrfToken\n },\n credentials: 'same-origin',\n body: JSON.stringify(body)\n });\n const data = await res.json();\n\n if (!res.ok || !data.success) {\n placeholder.remove();\n console.error('Failed to create sub-page', data && data.errors);\n return;\n }\n\n const meta = {\n url: data.redirect_url || data.page.url,\n icon: data.page.type_icon_emoji || this.defaultIconForType(data.page.type),\n title: data.page.title || 'Untitled',\n uuid: data.page.uuid\n };\n\n const linkBlock = this.createBlockElement({\n type: 'page_link',\n content: '',\n meta: meta,\n id: this.generateId()\n }, 0);\n\n placeholder.replaceWith(linkBlock);\n\n // Insert a fresh empty text block underneath so typing can continue.\n const followUp = this.createBlockElement({ type: 'text', content: '', id: this.generateId() }, 0);\n linkBlock.after(followUp);\n followUp.querySelector('.block-content')?.focus();\n\n if (typeof lucide !== 'undefined') lucide.createIcons();\n this.scheduleAutoSave();\n } catch (err) {\n placeholder.remove();\n console.error('Sub-page creation failed', err);\n }\n },\n\n defaultIconForType(typeSlug) {\n switch (typeSlug) {\n case 'task_board': return '\uD83D\uDCCB';\n case 'document':\n case 'page': return '\uD83D\uDCC4';\n case 'table':\n case 'spreadsheet':return '\uD83D\uDCCA';\n case 'project': return '\uD83D\uDCC1';\n default: return '\uD83D\uDCDD';\n }\n },\n\n // \u2500\u2500 Media blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Render a media block (image / video / audio / file / bookmark) into the\n // supplied .block-line container. The asset metadata lives on\n // div.dataset.meta so blocksToMarkdown can re-emit it.\n renderMediaBlock(div, block) {\n const meta = block.meta || {};\n div.dataset.meta = JSON.stringify(meta);\n\n // No URL yet: render a \"uploading\" placeholder. Used briefly between\n // the user picking a file and the upload completing.\n if (!meta.url) {\n const ph = document.createElement('div');\n ph.className = 'flex items-center gap-2 flex-1 px-3 py-2 text-[13px] text-ink-3 italic bg-bg-3 rounded';\n ph.innerHTML = ' Uploading\u2026';\n div.appendChild(ph);\n return;\n }\n\n if (block.type === 'image') {\n const fig = document.createElement('figure');\n fig.className = 'flex-1 my-1';\n const img = document.createElement('img');\n img.src = meta.url;\n img.alt = meta.caption || meta.name || 'Image';\n img.className = 'max-w-full max-h-[600px] rounded-md block';\n img.loading = 'lazy';\n fig.appendChild(img);\n fig.appendChild(this.buildCaption(meta.caption));\n div.appendChild(fig);\n return;\n }\n\n if (block.type === 'video') {\n const fig = document.createElement('figure');\n fig.className = 'flex-1 my-1';\n const video = document.createElement('video');\n video.src = meta.url;\n video.controls = true;\n video.className = 'max-w-full max-h-[600px] rounded-md block bg-black';\n fig.appendChild(video);\n fig.appendChild(this.buildCaption(meta.caption));\n div.appendChild(fig);\n return;\n }\n\n if (block.type === 'audio') {\n const fig = document.createElement('figure');\n fig.className = 'flex-1 my-1';\n const audio = document.createElement('audio');\n audio.src = meta.url;\n audio.controls = true;\n audio.className = 'w-full block';\n fig.appendChild(audio);\n fig.appendChild(this.buildCaption(meta.caption));\n div.appendChild(fig);\n return;\n }\n\n if (block.type === 'file') {\n const link = document.createElement('a');\n link.href = meta.url;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.className = 'flex items-center gap-3 flex-1 px-3 py-2 rounded-md border border-line bg-bg-3 hover:bg-bg-2 no-underline text-ink-1 transition-colors';\n const sizeStr = meta.size ? this.formatFileSize(meta.size) : '';\n link.innerHTML =\n '' +\n '' + this.escapeHtml(meta.name || meta.url) + '' +\n (sizeStr ? '' + this.escapeHtml(sizeStr) + '' : '') +\n '';\n div.appendChild(link);\n return;\n }\n\n if (block.type === 'bookmark') {\n const link = document.createElement('a');\n // Defense-in-depth: even if a bad URL was somehow persisted, only\n // honour http(s) hrefs to avoid `javascript:` / `data:` XSS at render.\n const safeHref = /^https?:\\/\\//i.test(meta.url || '') ? meta.url : '#';\n link.href = safeHref;\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.className = 'flex items-start gap-3 flex-1 p-3 rounded-md border border-line bg-bg-3 hover:bg-bg-2 no-underline text-ink-1 transition-colors';\n let host = '';\n try { host = new URL(meta.url).host; } catch (_) { host = meta.url; }\n link.innerHTML =\n '' +\n '
' +\n '
' + this.escapeHtml(meta.title || host || meta.url) + '
' +\n (meta.description ? '
' + this.escapeHtml(meta.description) + '
' : '') +\n '
' + this.escapeHtml(host || meta.url) + '
' +\n '
' +\n '';\n div.appendChild(link);\n return;\n }\n },\n\n buildCaption(initial) {\n const cap = document.createElement('figcaption');\n cap.className = 'block-caption text-[13px] text-ink-3 italic mt-1.5 outline-none';\n cap.contentEditable = true;\n cap.textContent = initial || '';\n cap.dataset.placeholder = 'Add a caption\u2026';\n cap.addEventListener('input', () => this.scheduleAutoSave());\n return cap;\n },\n\n formatFileSize(bytes) {\n if (!bytes) return '';\n const units = ['B', 'KB', 'MB', 'GB'];\n let i = 0;\n let n = bytes;\n while (n >= 1024 && i < units.length - 1) { n /= 1024; i++; }\n return (i === 0 ? Math.round(n) : n.toFixed(1)) + ' ' + units[i];\n },\n\n // Begin inserting a media block. For uploadable types this opens a file\n // picker; for `bookmark` it prompts for a URL. The current block line is\n // either replaced (if empty) or used as the anchor for an `after()` insert.\n insertMediaBlock(blockLine, type) {\n // Strip any \"/query\" the user typed before triggering the menu.\n const content = blockLine.querySelector('.block-content');\n if (content && this.slashStartPos !== null) {\n content.textContent = (content.textContent || '').slice(0, this.slashStartPos);\n }\n\n if (type === 'bookmark') {\n const raw = window.prompt('Enter URL', 'https://');\n if (!raw || !raw.trim()) return;\n const url = raw.trim();\n // Reject anything that isn't an http(s) URL \u2014 a `javascript:` or `data:`\n // href in an `` would be an XSS vector when the bookmark is rendered.\n if (!/^https?:\\/\\//i.test(url)) {\n window.alert('Please enter a URL starting with http:// or https://');\n return;\n }\n this.insertReadyMediaBlock(blockLine, type, { url, title: '', description: '' });\n return;\n }\n\n const input = document.createElement('input');\n input.type = 'file';\n if (type === 'image') input.accept = 'image/*';\n if (type === 'video') input.accept = 'video/*';\n if (type === 'audio') input.accept = 'audio/*';\n // type === 'file' accepts anything\n\n input.addEventListener('change', () => {\n const file = input.files && input.files[0];\n if (!file) return;\n this.uploadMediaForBlock(blockLine, type, file);\n });\n input.click();\n },\n\n // Place a fully-formed media block (with known meta) into the editor.\n insertReadyMediaBlock(blockLine, type, meta) {\n const isEmpty = this.blockHasNoTextContent(blockLine);\n const newBlock = this.createBlockElement({\n type, content: '', meta, id: this.generateId()\n }, 0);\n\n if (isEmpty) {\n blockLine.replaceWith(newBlock);\n } else {\n blockLine.after(newBlock);\n }\n\n // Ensure there's a fresh empty text block right after for continued typing.\n if (!newBlock.nextElementSibling) {\n const followUp = this.createBlockElement({ type: 'text', content: '', id: this.generateId() }, 0);\n newBlock.after(followUp);\n followUp.querySelector('.block-content')?.focus();\n }\n\n if (typeof lucide !== 'undefined') lucide.createIcons();\n this.scheduleAutoSave();\n },\n\n blockHasNoTextContent(blockLine) {\n const c = blockLine.querySelector('.block-content');\n if (!c) return false;\n return !c.textContent.trim();\n },\n\n // Upload a chosen file, showing a placeholder block while it's in flight.\n async uploadMediaForBlock(sourceBlockLine, type, file) {\n if (!this.uploadMediaUrl) {\n console.error('Block editor: data-upload-media-url is not configured');\n return;\n }\n\n const isEmpty = this.blockHasNoTextContent(sourceBlockLine);\n const placeholder = this.createBlockElement({\n type, content: '', meta: {}, id: this.generateId()\n }, 0);\n\n if (isEmpty) {\n sourceBlockLine.replaceWith(placeholder);\n } else {\n sourceBlockLine.after(placeholder);\n }\n if (typeof lucide !== 'undefined') lucide.createIcons();\n\n const fd = new FormData();\n fd.append('file', file);\n\n try {\n const res = await fetch(this.uploadMediaUrl, {\n method: 'POST',\n headers: {\n 'X-CSRF-Token': this.csrfToken,\n 'Accept': 'application/json'\n },\n credentials: 'same-origin',\n body: fd\n });\n const data = await res.json();\n\n if (!res.ok || !data.success) {\n placeholder.remove();\n window.alert((data && data.error) || 'Upload failed');\n return;\n }\n\n const meta = {\n url: data.url,\n name: data.name,\n size: data.size,\n content_type: data.content_type\n };\n\n const finalBlock = this.createBlockElement({\n type, content: '', meta, id: this.generateId()\n }, 0);\n placeholder.replaceWith(finalBlock);\n\n // Insert a follow-up empty text block underneath if the editor doesn't\n // already have one \u2014 keeps typing flow uninterrupted.\n if (!finalBlock.nextElementSibling) {\n const followUp = this.createBlockElement({ type: 'text', content: '', id: this.generateId() }, 0);\n finalBlock.after(followUp);\n }\n\n if (typeof lucide !== 'undefined') lucide.createIcons();\n this.scheduleAutoSave();\n } catch (err) {\n placeholder.remove();\n console.error('Media upload failed', err);\n window.alert('Upload failed');\n }\n },\n\n escapeHtml(s) {\n return String(s)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"');\n },\n\n insertBlockAfter(blockLine, type = 'text') {\n const newBlock = this.createBlockElement({\n type: type,\n content: '',\n id: this.generateId()\n }, 0);\n\n if (blockLine) {\n blockLine.after(newBlock);\n } else {\n this.blocksContainer.appendChild(newBlock);\n }\n\n this.updateNumberedLists();\n\n // Focus the new block\n const content = newBlock.querySelector('.block-content');\n if (content) {\n content.focus();\n }\n\n // Re-init icons\n if (typeof lucide !== 'undefined') {\n lucide.createIcons();\n }\n\n this.scheduleAutoSave();\n },\n\n scheduleAutoSave() {\n if (this.saveTimeout) {\n clearTimeout(this.saveTimeout);\n }\n this.saveTimeout = setTimeout(() => this.saveContent(), 1000);\n },\n\n async saveContent() {\n if (!this.saveUrl || !this.csrfToken) return;\n\n const content = this.blocksToMarkdown();\n const title = (this.titleInput?.value || '').trim();\n\n try {\n const response = await fetch(this.saveUrl, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n 'X-CSRF-Token': this.csrfToken\n },\n body: JSON.stringify({ content, title })\n });\n\n if (response.ok) {\n // Show save indicator briefly\n const indicator = document.getElementById('save-indicator');\n if (indicator) {\n indicator.classList.remove('hidden');\n setTimeout(() => indicator.classList.add('hidden'), 2000);\n }\n\n // Sync the sidebar row + breadcrumb when the title changes, so the user\n // doesn't have to refresh to see the new name.\n if (title && title !== this._lastSyncedTitle) {\n this._lastSyncedTitle = title;\n if (window.KozadoSidebar && this.pageId) {\n window.KozadoSidebar.updatePage(this.pageId, { title: title });\n }\n var crumb = document.querySelector('#page-breadcrumb-current');\n if (crumb) crumb.textContent = title;\n if (typeof document !== 'undefined') document.title = title + ' \u00B7 Kozado';\n }\n }\n } catch (error) {\n console.error('Failed to save:', error);\n }\n },\n\n generateId() {\n return 'block-' + Math.random().toString(36).substr(2, 9);\n },\n\n // \u2500\u2500 Rich-text content helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Allowed inline formatting tags. `style` is permitted so execCommand-\n // produced color spans (e.g. ``) round-trip.\n sanitizeRich(html) {\n if (!window.DOMPurify) return html;\n return window.DOMPurify.sanitize(html, {\n ALLOWED_TAGS: ['b', 'strong', 'i', 'em', 'u', 's', 'strike', 'br', 'a', 'span', 'mark', 'code', 'font'],\n ALLOWED_ATTR: ['href', 'target', 'rel', 'class', 'style', 'color']\n });\n },\n\n // \u2500\u2500 Selection toolbar (inline formatting) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Floating pill that appears above the current selection inside any\n // .block-content. Uses document.execCommand for formatting commands \u2014\n // deprecated but adequate for this surface and consistent with the\n // table-cell editor.\n buildSelectionToolbar() {\n if (this.selectionToolbar) return;\n const bar = document.createElement('div');\n bar.id = 'block-selection-toolbar';\n bar.className = 'hidden fixed z-[60] flex items-center gap-px p-1 bg-canvas border border-line rounded-lg shadow-2xl';\n\n const btn = (cmd, inner, title) =>\n ``;\n\n bar.innerHTML =\n btn('bold', 'B', 'Bold (\u2318B)') +\n btn('italic', 'I', 'Italic (\u2318I)') +\n btn('underline', 'U', 'Underline (\u2318U)') +\n btn('strikeThrough', 'S', 'Strikethrough') +\n '' +\n `` +\n '' +\n btn('createLink', '', 'Add link');\n\n // Color popover (built once, toggled by the color button)\n const palette = document.createElement('div');\n palette.className = 'hidden absolute top-full left-0 mt-1 p-2 bg-canvas border border-line rounded-lg shadow-2xl';\n palette.dataset.colorPalette = '';\n palette.innerHTML =\n '
Text color
' +\n '
' +\n this.TEXT_COLORS.map(c =>\n ``\n ).join('') +\n '
';\n bar.appendChild(palette);\n\n // Keep selection on mousedown\n bar.addEventListener('mousedown', (e) => {\n if (e.target.closest('button')) e.preventDefault();\n });\n\n bar.addEventListener('click', (e) => {\n const colorBtn = e.target.closest('[data-color]');\n if (colorBtn) {\n e.preventDefault();\n const hex = colorBtn.dataset.color;\n this.applyTextColor(hex);\n palette.classList.add('hidden');\n return;\n }\n\n const fmtBtn = e.target.closest('[data-fmt-cmd]');\n if (!fmtBtn) return;\n e.preventDefault();\n const cmd = fmtBtn.dataset.fmtCmd;\n if (cmd === 'color') {\n palette.classList.toggle('hidden');\n return;\n }\n palette.classList.add('hidden');\n if (cmd === 'createLink') {\n const url = window.prompt('Enter URL', 'https://');\n if (!url) return;\n document.execCommand('createLink', false, url);\n // Decorate inserted links so they're styled and open in new tab.\n const block = this.getSelectionBlock();\n block?.querySelectorAll('a').forEach(a => {\n if (!a.target) a.target = '_blank';\n if (!a.rel) a.rel = 'noopener noreferrer';\n if (!a.className) a.className = 'text-brand hover:underline';\n });\n } else {\n document.execCommand(cmd, false, null);\n }\n this.updateToolbarActiveStates();\n this.scheduleAutoSave();\n });\n\n document.body.appendChild(bar);\n this.selectionToolbar = bar;\n this.colorPalette = palette;\n },\n\n // Returns the .block-content element holding the current selection, if\n // any, and only when that block belongs to this editor and supports\n // rich text. Otherwise returns null.\n getSelectionBlock() {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return null;\n\n const range = sel.getRangeAt(0);\n let node = range.commonAncestorContainer;\n if (node.nodeType === Node.TEXT_NODE) node = node.parentNode;\n\n const block = node.closest && node.closest('.block-content');\n if (!block) return null;\n\n const blockLine = block.closest('.block-line');\n if (!blockLine || !this.blocksContainer.contains(blockLine)) return null;\n\n const type = blockLine.dataset.blockType;\n if (!this.RICH_TEXT_TYPES.includes(type)) return null;\n\n return block;\n },\n\n updateSelectionToolbar() {\n const block = this.getSelectionBlock();\n if (!block) {\n this.hideSelectionToolbar();\n return;\n }\n this.showSelectionToolbar();\n this.repositionSelectionToolbar();\n this.updateToolbarActiveStates();\n },\n\n showSelectionToolbar() {\n if (!this.selectionToolbar) return;\n this.selectionToolbar.classList.remove('hidden');\n },\n\n hideSelectionToolbar() {\n if (!this.selectionToolbar) return;\n this.selectionToolbar.classList.add('hidden');\n if (this.colorPalette) this.colorPalette.classList.add('hidden');\n },\n\n repositionSelectionToolbar() {\n if (!this.selectionToolbar || this.selectionToolbar.classList.contains('hidden')) return;\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const rect = sel.getRangeAt(0).getBoundingClientRect();\n if (rect.width === 0 && rect.height === 0) return;\n const bar = this.selectionToolbar;\n const top = Math.max(8, rect.top - bar.offsetHeight - 8);\n const left = Math.max(8, Math.min(window.innerWidth - bar.offsetWidth - 8, rect.left + rect.width / 2 - bar.offsetWidth / 2));\n bar.style.top = top + 'px';\n bar.style.left = left + 'px';\n },\n\n updateToolbarActiveStates() {\n if (!this.selectionToolbar) return;\n ['bold', 'italic', 'underline', 'strikeThrough'].forEach(cmd => {\n let on = false;\n try { on = document.queryCommandState(cmd); } catch (_) {}\n const btn = this.selectionToolbar.querySelector(`[data-fmt-cmd=\"${cmd}\"]`);\n if (btn) btn.dataset.active = on ? 'true' : 'false';\n });\n },\n\n applyTextColor(hex) {\n if (hex && hex.length) {\n document.execCommand('foreColor', false, hex);\n this.scheduleAutoSave();\n return;\n }\n\n // \"Default\" color \u2014 strip inline color from any element that intersects\n // the current selection. execCommand('foreColor', 'inherit'/'') is broken\n // across browsers (some apply a default red), so we do it manually.\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n const block = this.getSelectionBlock();\n if (!block) return;\n\n const intersects = (el) => {\n try { return range.intersectsNode(el); } catch (_) { return false; }\n };\n\n block.querySelectorAll('[style*=\"color\"]').forEach(el => {\n if (!intersects(el)) return;\n el.style.color = '';\n if (!el.getAttribute('style')) el.removeAttribute('style');\n // Unwrap empty-shell spans (no attrs, no class) so we don't leave noise.\n if (el.tagName === 'SPAN' && !el.attributes.length) {\n const parent = el.parentNode;\n while (el.firstChild) parent.insertBefore(el.firstChild, el);\n parent.removeChild(el);\n }\n });\n block.querySelectorAll('font[color]').forEach(el => {\n if (!intersects(el)) return;\n el.removeAttribute('color');\n if (!el.attributes.length) {\n const parent = el.parentNode;\n while (el.firstChild) parent.insertBefore(el.firstChild, el);\n parent.removeChild(el);\n }\n });\n this.scheduleAutoSave();\n },\n\n // \u2500\u2500 Block actions menu (drag handle click) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Notion-style: click the grip icon to open a small popover with\n // Delete / Duplicate / Turn Into options.\n buildBlockActionsMenu() {\n if (this.blockActionsMenu) return;\n const menu = document.createElement('div');\n menu.id = 'block-actions-menu';\n menu.className = 'hidden fixed z-[60] w-56 bg-canvas border border-line rounded-xl shadow-2xl py-1 text-[13px]';\n\n const item = (action, icon, label, hint) =>\n ``;\n\n const turnIntoTypes = [\n { type: 'text', label: 'Text', icon: 'type' },\n { type: 'heading1', label: 'Heading 1', icon: 'heading-1' },\n { type: 'heading2', label: 'Heading 2', icon: 'heading-2' },\n { type: 'heading3', label: 'Heading 3', icon: 'heading-3' },\n { type: 'bullet', label: 'Bulleted list', icon: 'list' },\n { type: 'numbered', label: 'Numbered list', icon: 'list-ordered' },\n { type: 'todo', label: 'To-do list', icon: 'square-check' },\n { type: 'quote', label: 'Quote', icon: 'quote' },\n { type: 'callout', label: 'Callout', icon: 'alert-circle' },\n { type: 'code', label: 'Code', icon: 'code' },\n { type: 'divider', label: 'Divider', icon: 'minus' },\n ];\n\n menu.innerHTML =\n item('delete', 'trash-2', 'Delete', 'Del') +\n item('duplicate', 'copy', 'Duplicate', '\u2318D') +\n '
' +\n '
Turn into
' +\n '
' +\n turnIntoTypes.map(t =>\n ``\n ).join('') +\n '
';\n\n menu.addEventListener('click', (e) => {\n const btn = e.target.closest('[data-action]');\n if (!btn) return;\n e.preventDefault();\n e.stopPropagation();\n const action = btn.dataset.action;\n const blockLine = this.currentActionsBlock;\n if (!blockLine) return;\n if (action === 'delete') {\n this.deleteBlock(blockLine);\n } else if (action === 'duplicate') {\n this.duplicateBlock(blockLine);\n } else if (action === 'turn-into') {\n this.turnIntoType(blockLine, btn.dataset.type);\n }\n this.hideBlockActionsMenu();\n });\n\n document.body.appendChild(menu);\n this.blockActionsMenu = menu;\n },\n\n showBlockActionsMenu(anchorEl, blockLine) {\n this.buildBlockActionsMenu();\n const menu = this.blockActionsMenu;\n this.currentActionsBlock = blockLine;\n\n // Position to the right of the drag handle, clamped to viewport.\n const rect = anchorEl.getBoundingClientRect();\n menu.classList.remove('hidden');\n // After unhide, compute size to clamp.\n const w = menu.offsetWidth;\n const h = menu.offsetHeight;\n let left = rect.right + 6;\n let top = rect.top;\n if (left + w + 8 > window.innerWidth) left = Math.max(8, rect.left - w - 6);\n if (top + h + 8 > window.innerHeight) top = Math.max(8, window.innerHeight - h - 8);\n menu.style.left = left + 'px';\n menu.style.top = top + 'px';\n\n // Re-init lucide icons for the freshly-rendered icons.\n if (typeof lucide !== 'undefined') lucide.createIcons();\n },\n\n hideBlockActionsMenu() {\n if (!this.blockActionsMenu) return;\n this.blockActionsMenu.classList.add('hidden');\n this.currentActionsBlock = null;\n },\n\n deleteBlock(blockLine) {\n if (!blockLine || !blockLine.parentNode) return;\n // Don't leave the editor with zero blocks \u2014 replace with an empty text block.\n const isOnly = this.blocksContainer.children.length <= 1;\n if (isOnly) {\n const empty = this.createBlockElement({ type: 'text', content: '', id: this.generateId() }, 0);\n blockLine.replaceWith(empty);\n empty.querySelector('.block-content')?.focus();\n } else {\n const focusTarget = blockLine.previousElementSibling || blockLine.nextElementSibling;\n blockLine.remove();\n focusTarget?.querySelector('.block-content')?.focus();\n }\n this.updateNumberedLists();\n if (typeof lucide !== 'undefined') lucide.createIcons();\n this.scheduleAutoSave();\n },\n\n duplicateBlock(blockLine) {\n if (!blockLine) return;\n const type = blockLine.dataset.blockType;\n const contentEl = blockLine.querySelector('.block-content');\n const block = {\n type,\n id: this.generateId(),\n content: ''\n };\n if (contentEl) {\n block.content = type === 'code' ? (contentEl.textContent || '') : this.sanitizeRich(contentEl.innerHTML || '');\n }\n if (type === 'code') block.language = blockLine.dataset.language || '';\n if (type === 'numbered') block.number = parseInt(blockLine.dataset.number || '1', 10);\n if (type === 'todo') {\n const cb = blockLine.querySelector('input[type=\"checkbox\"]');\n block.checked = !!(cb && cb.checked);\n }\n if (type === 'page_link' && blockLine.dataset.meta) {\n try { block.meta = JSON.parse(blockLine.dataset.meta); } catch (_) { block.meta = {}; }\n }\n if (this.MEDIA_TYPES.includes(type) && blockLine.dataset.meta) {\n try { block.meta = JSON.parse(blockLine.dataset.meta); } catch (_) { block.meta = {}; }\n // Pull the latest caption back into meta \u2014 the user may have edited it\n // since the last save.\n const cap = blockLine.querySelector('.block-caption');\n if (cap) block.meta.caption = cap.textContent || '';\n }\n\n const newBlock = this.createBlockElement(block, 0);\n blockLine.after(newBlock);\n this.updateNumberedLists();\n if (typeof lucide !== 'undefined') lucide.createIcons();\n newBlock.querySelector('.block-content')?.focus();\n this.scheduleAutoSave();\n },\n\n // Convert a block to a new type, preserving inline-formatted content\n // when the source had any. Source/target may be any rich type, code,\n // or divider. page_link is intentionally not a turn-into target.\n turnIntoType(blockLine, newType) {\n if (!blockLine || !newType) return;\n const oldType = blockLine.dataset.blockType;\n if (oldType === newType) return;\n // Media blocks have no .block-content to convert from; \"Turn into\" would\n // silently drop the asset. Force the user to Delete + re-add instead.\n if (this.MEDIA_TYPES.includes(oldType)) return;\n\n const contentEl = blockLine.querySelector('.block-content');\n let html = '';\n if (contentEl) {\n html = oldType === 'code'\n ? this.escapeHtml(contentEl.textContent || '')\n : this.sanitizeRich(contentEl.innerHTML || '');\n }\n // When converting INTO code, we want plaintext only.\n if (newType === 'code') {\n const tmp = document.createElement('div');\n tmp.innerHTML = html;\n html = tmp.textContent || '';\n }\n if (newType === 'divider') html = '';\n\n const block = {\n type: newType,\n id: this.generateId(),\n content: html\n };\n if (newType === 'todo') {\n const cb = blockLine.querySelector('input[type=\"checkbox\"]');\n block.checked = !!(cb && cb.checked);\n }\n\n const replacement = this.createBlockElement(block, 0);\n blockLine.replaceWith(replacement);\n this.updateNumberedLists();\n if (typeof lucide !== 'undefined') lucide.createIcons();\n replacement.querySelector('.block-content')?.focus();\n this.scheduleAutoSave();\n },\n\n // Drag and drop handlers\n handleDragStart(e, blockLine) {\n this.draggedBlock = blockLine;\n blockLine.classList.add('opacity-50', 'bg-gray-100');\n\n // Create drop indicator if it doesn't exist\n if (!this.dropIndicator) {\n this.dropIndicator = document.createElement('div');\n this.dropIndicator.className = 'drop-indicator h-1 bg-kozado-500 rounded-full mx-8 my-1 hidden';\n }\n\n // Set drag data\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData('text/plain', blockLine.dataset.blockId);\n\n // Use a slight delay to allow the drag image to be captured\n setTimeout(() => {\n blockLine.classList.add('dragging');\n }, 0);\n },\n\n handleDragEnd(_e, blockLine) {\n blockLine.draggable = false;\n blockLine.classList.remove('opacity-50', 'bg-gray-100', 'dragging');\n\n // Remove drop indicator\n if (this.dropIndicator && this.dropIndicator.parentNode) {\n this.dropIndicator.remove();\n }\n\n // Remove all drag-over styling\n this.blocksContainer.querySelectorAll('.block-line').forEach(block => {\n block.classList.remove('drag-over-top', 'drag-over-bottom');\n });\n\n this.draggedBlock = null;\n },\n\n handleDragOver(e, blockLine) {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n\n if (!this.draggedBlock || this.draggedBlock === blockLine) return;\n\n // Determine if we're in the top or bottom half of the target block\n const rect = blockLine.getBoundingClientRect();\n const midY = rect.top + rect.height / 2;\n const isTopHalf = e.clientY < midY;\n\n // Clear previous indicators\n this.blocksContainer.querySelectorAll('.block-line').forEach(block => {\n block.classList.remove('drag-over-top', 'drag-over-bottom');\n });\n\n // Add indicator to current target\n if (isTopHalf) {\n blockLine.classList.add('drag-over-top');\n } else {\n blockLine.classList.add('drag-over-bottom');\n }\n },\n\n handleDragLeave(e, blockLine) {\n // Only remove if we're actually leaving the element\n const relatedTarget = e.relatedTarget;\n if (!blockLine.contains(relatedTarget)) {\n blockLine.classList.remove('drag-over-top', 'drag-over-bottom');\n }\n },\n\n handleDrop(e, blockLine) {\n e.preventDefault();\n\n if (!this.draggedBlock || this.draggedBlock === blockLine) return;\n\n // Determine drop position\n const rect = blockLine.getBoundingClientRect();\n const midY = rect.top + rect.height / 2;\n const dropBefore = e.clientY < midY;\n\n // Move the dragged block\n if (dropBefore) {\n blockLine.parentNode.insertBefore(this.draggedBlock, blockLine);\n } else {\n blockLine.parentNode.insertBefore(this.draggedBlock, blockLine.nextSibling);\n }\n\n // Update numbered list numbers if needed\n this.updateNumberedLists();\n\n // Clear styling\n this.blocksContainer.querySelectorAll('.block-line').forEach(block => {\n block.classList.remove('drag-over-top', 'drag-over-bottom');\n });\n\n // Trigger auto-save\n this.scheduleAutoSave();\n },\n\n // True when the caret is on the first (or last) visual line of `el`.\n // For an empty contentEditable the caret rect can be (0,0); fall back to\n // treating that as \"at the edge\" so navigation still works.\n isCaretAtEdgeLine(el, top) {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return true;\n const range = sel.getRangeAt(0).cloneRange();\n range.collapse(true);\n let caretRect = range.getBoundingClientRect();\n if (caretRect.top === 0 && caretRect.bottom === 0 && caretRect.left === 0) {\n // Empty / no measurable rect \u2014 treat as on the edge line.\n return true;\n }\n const elRect = el.getBoundingClientRect();\n // Allow ~half a line of slack so descenders/line-height padding don't\n // misclassify the first/last line.\n const lineHeight = parseFloat(getComputedStyle(el).lineHeight) || 20;\n const slack = lineHeight / 2;\n return top\n ? caretRect.top - elRect.top < slack\n : elRect.bottom - caretRect.bottom < slack;\n },\n\n findPrevEditableBlock(blockLine) {\n let el = blockLine?.previousElementSibling;\n while (el && !el.querySelector?.('.block-content')) el = el.previousElementSibling;\n return el || null;\n },\n\n findNextEditableBlock(blockLine) {\n let el = blockLine?.nextElementSibling;\n while (el && !el.querySelector?.('.block-content')) el = el.nextElementSibling;\n return el || null;\n },\n\n focusBlockContent(blockLine, position) {\n const content = blockLine.querySelector('.block-content');\n if (!content) return;\n content.focus();\n const range = document.createRange();\n range.selectNodeContents(content);\n range.collapse(position !== 'end');\n const sel = window.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n },\n\n updateNumberedLists() {\n // Re-number all numbered list items\n let number = 1;\n this.blocksContainer.querySelectorAll('.block-line').forEach(block => {\n if (block.dataset.blockType === 'numbered') {\n block.dataset.number = number;\n const content = block.querySelector('.block-content');\n if (content) {\n content.dataset.number = number;\n }\n number++;\n } else {\n // Reset counter when we hit a non-numbered block\n number = 1;\n }\n });\n }\n};\n\n// Initialize on DOM load\ndocument.addEventListener('DOMContentLoaded', () => {\n BlockEditor.init();\n});\n\n// Export for use in other scripts\nwindow.BlockEditor = BlockEditor;\n", "// Page actions menu controller \u2014 drives the floating \u2022\u2022\u2022 menu rendered by\n// shared/_page_actions_menu.html.erb and the move-to picker rendered by\n// shared/_move_to_modal.html.erb. Triggers (sidebar rows, show-page buttons)\n// just need [data-page-actions-trigger] + the data-page-* attributes the\n// partial documents at the top.\n//\n// Why a single shared menu element instead of per-trigger dropdowns:\n// - One DOM tree, one set of event listeners, no duplicate ids when the\n// sidebar renders dozens of page rows.\n// - Positioning is handled by JS, so the menu can fly out of overflow:hidden\n// sidebars without clipping.\n// - Keeps the show-page dropdowns lightweight \u2014 they delegate their actions\n// section to this controller and only own their cover/icon affordances.\n\ndocument.addEventListener('DOMContentLoaded', function () {\n const menu = document.getElementById('page-actions-menu');\n const modal = document.getElementById('move-to-modal');\n if (!menu) return; // Layout-rendered partial absent \u2014 bail silently.\n\n const csrf = (document.querySelector('meta[name=\"csrf-token\"]') || {}).content || '';\n\n // \u2500\u2500 Active context (whichever trigger most recently opened the menu) \u2500\u2500\u2500\n let active = null;\n let activeTriggerEl = null;\n\n function readContext(trigger) {\n return {\n pageId: trigger.dataset.pageId,\n pageTitle: trigger.dataset.pageTitle || 'Untitled',\n pageIcon: trigger.dataset.pageIcon || '\uD83D\uDCC4',\n pageUrl: trigger.dataset.pageUrl,\n starred: trigger.dataset.pageStarred === 'true',\n updateUrl: trigger.dataset.pageUpdateUrl,\n deleteUrl: trigger.dataset.pageDeleteUrl,\n duplicateUrl: trigger.dataset.pageDuplicateUrl,\n starUrl: trigger.dataset.pageToggleStarUrl,\n renameMode: trigger.dataset.renameMode || 'title-input',\n };\n }\n\n // \u2500\u2500 Toast (reused for every action's feedback) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // The show pages have their own #page-toast; for the sidebar we mint a\n // lightweight portable toast so feedback is uniform regardless of where\n // the user invoked the action.\n function showToast(msg, kind) {\n const existing = document.getElementById('koz-portable-toast');\n if (existing) existing.remove();\n const toast = document.createElement('div');\n toast.id = 'koz-portable-toast';\n const accent = kind === 'error' ? '#FF6B9E' : '#45D69B';\n toast.style.cssText =\n 'position:fixed;bottom:20px;right:20px;z-index:200;' +\n 'display:flex;align-items:center;gap:10px;' +\n 'padding:10px 14px;border-radius:10px;' +\n 'background:rgba(11,15,30,0.92);backdrop-filter:blur(12px);' +\n 'border:1px solid rgba(255,255,255,0.12);' +\n 'border-left:2px solid ' + accent + ';' +\n 'color:#F4F6FB;font-size:13px;font-weight:500;' +\n 'box-shadow:0 16px 32px -12px rgba(0,0,0,0.5);' +\n 'animation:fade-in 0.18s ease-out;';\n toast.textContent = msg;\n document.body.appendChild(toast);\n setTimeout(function () { toast.remove(); }, 2200);\n }\n\n // \u2500\u2500 Open / close / position \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n function openMenu(trigger) {\n activeTriggerEl = trigger;\n active = readContext(trigger);\n\n // Update the active label strip.\n const iconEl = document.getElementById('pam-active-icon');\n const titleEl = document.getElementById('pam-active-title');\n if (iconEl) iconEl.textContent = active.pageIcon;\n if (titleEl) titleEl.textContent = active.pageTitle;\n\n // Favorite label flips based on current state.\n const favLbl = document.getElementById('pam-favorite-label');\n if (favLbl) favLbl.textContent = active.starred ? 'Remove from Favorites' : 'Add to Favorites';\n\n // Reveal first to measure, then position.\n menu.classList.remove('hidden');\n positionMenu(trigger);\n\n // Re-init lucide icons inside the menu (they may not have rendered yet).\n if (window.lucide && window.lucide.createIcons) window.lucide.createIcons();\n }\n\n function closeMenu() {\n menu.classList.add('hidden');\n activeTriggerEl = null;\n }\n\n function positionMenu(trigger) {\n const rect = trigger.getBoundingClientRect();\n const menuRect = menu.getBoundingClientRect();\n const margin = 6;\n\n // Prefer placing the menu's top-left near the trigger's bottom-right.\n let left = rect.right - menuRect.width; // right-align with trigger\n let top = rect.bottom + margin;\n\n // Flip horizontally if it would overflow the left edge.\n if (left < 8) left = rect.left;\n\n // Flip vertically if it would overflow the bottom edge.\n if (top + menuRect.height > window.innerHeight - 8) {\n top = rect.top - menuRect.height - margin;\n }\n\n // Clamp so it never sits off-screen even on tiny viewports.\n left = Math.max(8, Math.min(left, window.innerWidth - menuRect.width - 8));\n top = Math.max(8, Math.min(top, window.innerHeight - menuRect.height - 8));\n\n menu.style.left = left + 'px';\n menu.style.top = top + 'px';\n }\n\n // \u2500\u2500 Trigger delegation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n document.addEventListener('click', function (e) {\n const trigger = e.target.closest('[data-page-actions-trigger]');\n if (trigger) {\n e.preventDefault();\n e.stopPropagation();\n // Toggle if same trigger; otherwise reopen on the new trigger.\n if (activeTriggerEl === trigger && !menu.classList.contains('hidden')) {\n closeMenu();\n } else {\n openMenu(trigger);\n }\n return;\n }\n // Click anywhere else closes the menu (but not the modal).\n if (!menu.contains(e.target)) closeMenu();\n });\n\n // Reposition on scroll/resize so the menu stays attached while open.\n window.addEventListener('scroll', function () { if (activeTriggerEl) positionMenu(activeTriggerEl); }, true);\n window.addEventListener('resize', function () { if (activeTriggerEl) positionMenu(activeTriggerEl); });\n\n // Esc closes either the menu or the modal.\n document.addEventListener('keydown', function (e) {\n if (e.key === 'Escape') {\n if (modal && !modal.classList.contains('hidden')) closeModal();\n else if (!menu.classList.contains('hidden')) closeMenu();\n }\n });\n\n // \u2500\u2500 Action dispatch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n menu.addEventListener('click', function (e) {\n const item = e.target.closest('[data-action]');\n if (!item || !active) return;\n const action = item.dataset.action;\n\n switch (action) {\n case 'favorite': return doFavorite();\n case 'copy-link': return doCopyLink();\n case 'duplicate': return doDuplicate();\n case 'rename': return doRename();\n case 'move': return openModal();\n case 'open-tab': return doOpenTab();\n case 'delete': return doDelete();\n }\n });\n\n async function doFavorite() {\n if (!active.starUrl) { showToast('No star endpoint', 'error'); closeMenu(); return; }\n try {\n const res = await fetch(active.starUrl, {\n method: 'POST',\n headers: { 'Accept': 'application/json', 'X-CSRF-Token': csrf },\n credentials: 'same-origin'\n });\n const data = await res.json().catch(function () { return {}; });\n if (res.ok && data.success) {\n const nowStarred = !!data.is_starred;\n showToast(nowStarred ? 'Added to Favorites' : 'Removed from Favorites');\n // Reflect new state on the trigger so a second open shows the right label.\n if (activeTriggerEl) activeTriggerEl.dataset.pageStarred = nowStarred ? 'true' : 'false';\n // Mirror to a separate star button on the same page if present.\n const starBtn = document.getElementById('star-btn');\n if (starBtn && starBtn.dataset.toggleUrl === active.starUrl) {\n starBtn.dataset.starred = nowStarred ? 'true' : 'false';\n const ic = starBtn.querySelector('svg');\n if (ic) {\n ic.classList.toggle('text-amber', nowStarred);\n ic.classList.toggle('fill-amber', nowStarred);\n }\n }\n } else {\n showToast('Could not update', 'error');\n }\n } catch (err) {\n console.error('Favorite failed', err);\n showToast('Network error', 'error');\n }\n closeMenu();\n }\n\n function doCopyLink() {\n const url = active.pageUrl ? new URL(active.pageUrl, window.location.origin).toString() : window.location.href;\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(url).then(function () {\n showToast('Link copied');\n }).catch(function () { showToast('Could not copy', 'error'); });\n } else {\n // Fallback for non-secure-context (rare in modern Rails dev, but not unheard of).\n const ta = document.createElement('textarea');\n ta.value = url; ta.style.position = 'fixed'; ta.style.opacity = '0';\n document.body.appendChild(ta); ta.select();\n try { document.execCommand('copy'); showToast('Link copied'); }\n catch (e) { showToast('Could not copy', 'error'); }\n document.body.removeChild(ta);\n }\n closeMenu();\n }\n\n async function doDuplicate() {\n if (!active.duplicateUrl) { showToast('Cannot duplicate', 'error'); closeMenu(); return; }\n try {\n const res = await fetch(active.duplicateUrl, {\n method: 'POST',\n headers: { 'Accept': 'application/json', 'X-CSRF-Token': csrf },\n credentials: 'same-origin'\n });\n const data = await res.json().catch(function () { return {}; });\n if (res.ok && data.success && data.redirect_url) {\n showToast('Duplicated \u2014 opening copy\u2026');\n setTimeout(function () { window.location.href = data.redirect_url; }, 350);\n } else {\n showToast((data.errors && data.errors[0]) || 'Could not duplicate', 'error');\n }\n } catch (err) {\n console.error('Duplicate failed', err);\n showToast('Network error', 'error');\n }\n closeMenu();\n }\n\n function doRename() {\n if (active.renameMode === 'title-input') {\n // On the page show: focus the existing title input and select its text.\n // The block editor's auto-save catches the blur.\n const input = document.getElementById('page-title-input');\n if (input) {\n input.focus();\n input.select();\n } else {\n showToast('No title field to focus', 'error');\n }\n } else if (active.renameMode === 'inline' && activeTriggerEl) {\n startInlineRename(activeTriggerEl);\n }\n closeMenu();\n }\n\n // Replace the sidebar row's link with a text input. On commit (Enter / blur),\n // PATCH the page and update the link's label without a page reload.\n function startInlineRename(trigger) {\n const row = trigger.closest('.page-tree-item');\n if (!row) return;\n const link = row.querySelector('a');\n if (!link) return;\n\n const labelSpan = link.querySelector('span.truncate');\n const currentTitle = labelSpan ? labelSpan.textContent.trim() : (active.pageTitle || '');\n\n const input = document.createElement('input');\n input.type = 'text';\n input.value = currentTitle;\n input.className = 'sidebar-rename-input';\n link.style.display = 'none';\n link.parentNode.insertBefore(input, link);\n input.focus();\n input.select();\n\n let committed = false;\n async function commit() {\n if (committed) return;\n committed = true;\n const newTitle = input.value.trim();\n input.remove();\n link.style.display = '';\n if (!newTitle || newTitle === currentTitle) return;\n try {\n const res = await fetch(active.updateUrl, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-Token': csrf },\n credentials: 'same-origin',\n body: JSON.stringify({ page: { title: newTitle } })\n });\n const data = await res.json().catch(function () { return {}; });\n if (res.ok && data.success) {\n if (labelSpan) labelSpan.textContent = newTitle;\n if (trigger) trigger.dataset.pageTitle = newTitle;\n showToast('Renamed');\n // The slug changed too; if the user clicks the link next, the\n // server-side controller redirects to the canonical URL.\n if (data.page && data.page.url) link.setAttribute('href', data.page.url);\n } else {\n showToast('Could not rename', 'error');\n }\n } catch (err) {\n console.error('Rename failed', err);\n showToast('Network error', 'error');\n }\n }\n function cancel() {\n if (committed) return;\n committed = true;\n input.remove();\n link.style.display = '';\n }\n input.addEventListener('keydown', function (e) {\n if (e.key === 'Enter') { e.preventDefault(); commit(); }\n if (e.key === 'Escape') { e.preventDefault(); cancel(); }\n });\n input.addEventListener('blur', commit);\n }\n\n function doOpenTab() {\n if (active.pageUrl) window.open(active.pageUrl, '_blank', 'noopener');\n closeMenu();\n }\n\n async function doDelete() {\n closeMenu();\n if (!active.deleteUrl) { showToast('Cannot delete', 'error'); return; }\n if (!confirm('Move \"' + active.pageTitle + '\" to trash? This will also remove every sub-page underneath it.')) return;\n try {\n const res = await fetch(active.deleteUrl, {\n method: 'DELETE',\n headers: { 'Accept': 'application/json', 'X-CSRF-Token': csrf },\n credentials: 'same-origin'\n });\n const data = await res.json().catch(function () { return {}; });\n if (res.ok && data.success) {\n // If we're currently looking at the deleted page, follow the redirect.\n const onThisPage = window.location.pathname === active.pageUrl;\n if (onThisPage && data.redirect_url) {\n window.location.href = data.redirect_url;\n } else {\n // Otherwise just yank the row from the sidebar without reloading.\n const row = activeTriggerEl && activeTriggerEl.closest('.page-tree-item');\n if (row) row.remove();\n showToast('Moved to Trash');\n }\n } else {\n showToast('Could not delete', 'error');\n }\n } catch (err) {\n console.error('Delete failed', err);\n showToast('Network error', 'error');\n }\n }\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // MOVE-TO MODAL\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n if (!modal) return;\n\n const backdrop = document.getElementById('move-to-backdrop');\n const closeBtn = document.getElementById('move-to-close');\n const searchEl = document.getElementById('move-to-search');\n const listEl = document.getElementById('move-to-list');\n const emptyEl = document.getElementById('move-to-empty');\n const subjectEl = document.getElementById('move-to-subject');\n const countEl = document.getElementById('move-to-count');\n const allRows = function () { return Array.from(listEl.querySelectorAll('.move-to-row')); };\n\n function openModal() {\n closeMenu();\n if (!active) return;\n\n subjectEl.textContent = 'Moving \"' + active.pageTitle + '\"';\n\n // Mark invalid destinations: self + every descendant of the page being moved.\n // We fetch descendants by walking the page-tree-item DOM in the sidebar \u2014 this\n // is fast (no roundtrip) and accurate as long as the sidebar shows the page\n // tree (which it does on every authenticated screen).\n const invalidIds = new Set([String(active.pageId)]);\n const sidebarRow = document.querySelector('.page-tree-item[data-page-id=\"' + active.pageId + '\"]');\n if (sidebarRow) {\n sidebarRow.querySelectorAll('.page-tree-item').forEach(function (el) {\n invalidIds.add(String(el.dataset.pageId));\n });\n }\n\n // Reset filter state, mark current parent + invalid targets, count visible.\n let visible = 0;\n allRows().forEach(function (row) {\n const id = row.dataset.targetId;\n const invalid = invalidIds.has(String(id));\n row.dataset.disabled = invalid ? 'true' : 'false';\n row.classList.remove('is-active', 'is-current');\n row.style.display = '';\n // Mark the current parent visually so users know where the page lives now.\n if (activeTriggerEl && activeTriggerEl.dataset.parentId === id) row.classList.add('is-current');\n if (!invalid) visible++;\n });\n refreshCount(visible);\n\n searchEl.value = '';\n showAllGroups();\n modal.classList.remove('hidden');\n setTimeout(function () { searchEl.focus(); }, 30);\n if (window.lucide && window.lucide.createIcons) window.lucide.createIcons();\n }\n\n function closeModal() {\n modal.classList.add('hidden');\n }\n\n function refreshCount(n) {\n if (!countEl) return;\n countEl.textContent = n + ' destination' + (n === 1 ? '' : 's');\n }\n\n // Hide group labels whose every row is filtered out.\n function showAllGroups() {\n listEl.querySelectorAll('.move-to-group-label').forEach(function (l) { l.style.display = ''; });\n }\n function recomputeGroupVisibility() {\n const labels = listEl.querySelectorAll('.move-to-group-label');\n labels.forEach(function (label) {\n const groupName = label.dataset.group;\n const anyVisible = listEl.querySelectorAll(\n '.move-to-row[data-target-project=\"' + cssEscape(groupName) + '\"]'\n );\n let shown = 0;\n anyVisible.forEach(function (r) { if (r.style.display !== 'none') shown++; });\n label.style.display = shown ? '' : 'none';\n });\n }\n\n // Light CSS.escape polyfill \u2014 modern browsers support CSS.escape, but we\n // route through this helper anyway so the call sites stay readable.\n function cssEscape(v) {\n if (window.CSS && CSS.escape) return CSS.escape(v);\n return String(v).replace(/([\"\\\\])/g, '\\\\$1');\n }\n\n // Search filter \u2014 case-insensitive substring on title; empty query restores all.\n if (searchEl) {\n searchEl.addEventListener('input', function () {\n const q = searchEl.value.trim().toLowerCase();\n let visible = 0;\n let firstActive = null;\n allRows().forEach(function (row) {\n const title = (row.dataset.targetTitle || '').toLowerCase();\n const proj = (row.dataset.targetProject || '').toLowerCase();\n const matches = !q || title.indexOf(q) !== -1 || proj.indexOf(q) !== -1;\n const disabled = row.dataset.disabled === 'true';\n const show = matches && !disabled;\n row.style.display = show ? '' : 'none';\n row.classList.remove('is-active');\n if (show) {\n visible++;\n if (!firstActive) firstActive = row;\n }\n });\n if (firstActive) firstActive.classList.add('is-active');\n if (emptyEl) emptyEl.classList.toggle('hidden', visible > 0);\n recomputeGroupVisibility();\n refreshCount(visible);\n });\n\n // Keyboard navigation through the visible rows.\n searchEl.addEventListener('keydown', function (e) {\n if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Enter') return;\n const visibleRows = allRows().filter(function (r) {\n return r.style.display !== 'none' && r.dataset.disabled !== 'true';\n });\n if (visibleRows.length === 0) return;\n const currentIdx = visibleRows.findIndex(function (r) { return r.classList.contains('is-active'); });\n if (e.key === 'Enter') {\n e.preventDefault();\n const target = currentIdx >= 0 ? visibleRows[currentIdx] : visibleRows[0];\n target.click();\n return;\n }\n e.preventDefault();\n let next;\n if (e.key === 'ArrowDown') next = currentIdx < visibleRows.length - 1 ? currentIdx + 1 : 0;\n else next = currentIdx > 0 ? currentIdx - 1 : visibleRows.length - 1;\n visibleRows.forEach(function (r) { r.classList.remove('is-active'); });\n visibleRows[next].classList.add('is-active');\n visibleRows[next].scrollIntoView({ block: 'nearest' });\n });\n }\n\n // Hover sets the active row (so keyboard + mouse stay in sync).\n if (listEl) {\n listEl.addEventListener('mouseover', function (e) {\n const row = e.target.closest('.move-to-row');\n if (!row || row.dataset.disabled === 'true') return;\n allRows().forEach(function (r) { r.classList.remove('is-active'); });\n row.classList.add('is-active');\n });\n\n // Click commits the move via PATCH /pages/:id with parent_id.\n listEl.addEventListener('click', function (e) {\n const row = e.target.closest('.move-to-row');\n if (!row || row.dataset.disabled === 'true') return;\n commitMove(row);\n });\n }\n\n if (closeBtn) closeBtn.addEventListener('click', closeModal);\n if (backdrop) backdrop.addEventListener('click', closeModal);\n\n async function commitMove(row) {\n if (!active || !active.updateUrl) return;\n const targetId = row.dataset.targetId;\n const targetTitle = row.dataset.targetTitle;\n try {\n const res = await fetch(active.updateUrl, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-Token': csrf },\n credentials: 'same-origin',\n body: JSON.stringify({ page: { parent_id: targetId } })\n });\n const data = await res.json().catch(function () { return {}; });\n if (res.ok && data.success) {\n showToast('Moved to ' + targetTitle);\n closeModal();\n // Reload so the sidebar tree + breadcrumbs reflect the new parenting.\n // Reparenting touches multiple panes (sidebar, breadcrumb, unlinked\n // sub-pages section) so a clean reload is more reliable than trying to\n // patch every region in place.\n setTimeout(function () { window.location.reload(); }, 350);\n } else {\n showToast((data.errors && data.errors[0]) || 'Could not move', 'error');\n }\n } catch (err) {\n console.error('Move failed', err);\n showToast('Network error', 'error');\n }\n }\n});\n"], "mappings": "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", "names": ["sidebarToggle", "primarySidebar", "navbarLogoSection", "isCollapsed", "workspaceDropdownBtn", "workspaceDropdown", "closeWorkspaceDropdown", "e", "item", "slug", "quickSearchBtn", "headerSearchBtn", "searchOverlay", "globalSearchInput", "openSearch", "closeSearch", "closeNotifications", "closeUserDropdown", "notificationsBtn", "notificationsPanel", "userDropdownBtn", "userDropdown", "btn", "alert", "el", "init", "panel", "currentUserId", "pusherKey", "pusherCluster", "btn", "dot", "listEl", "emptyEl", "markAllBtn", "notifications", "unreadCount", "updateDot", "updateMarkAllState", "escapeHtml", "s", "GRADIENTS", "gradientFor", "id", "n", "renderItem", "actor", "initials", "avatar", "unreadDot", "bodyHtml", "rowClasses", "render", "applyState", "items", "count", "fetchNotifications", "r", "data", "e", "row", "url", "wasUnread", "dotSpan", "pusher", "channel", "COLORS", "BY_NAME", "BY_HEX", "c", "name", "hex", "colorOrHex", "escapeHtml", "s", "opts", "value", "options", "onChange", "placeholder", "wrap", "trigger", "labelEl", "panel", "optionInner", "o", "bits", "sw", "renderTrigger", "found", "renderPanel", "empty", "item", "isActive", "e", "choose", "outsideHandler", "open", "close", "v", "values", "chipBox", "chev", "renderChips", "active", "idx", "escapeHtml", "s", "colorList", "colorByName", "n", "activePicker", "closeColorPicker", "openColorPicker", "anchor", "currentColor", "onPick", "picker", "c", "dot", "e", "rect", "pickerRect", "outside", "opts", "onChange", "compact", "root", "listEl", "addBtn", "addChoice", "emit", "getChoices", "row", "out", "applySwatchStyle", "el", "color", "buildRow", "choice", "label", "grip", "swatch", "newColor", "input", "removeRow", "del", "wireDrag", "focusPrev", "prev", "i", "dragSrc", "before", "initial", "palette", "current", "nextColor", "setChoices", "arr", "normalized", "empty", "TaskModal", "taskId", "boardId", "response", "task", "overlay", "error", "taskTags", "boardTags", "container", "tag", "hex", "pill", "e", "btn", "anchor", "pop", "search", "listEl", "createWrap", "createBtn", "createLabel", "renderList", "empty", "checkedIds", "t", "row", "willAdd", "q", "visible", "exact", "r", "match", "name", "created", "a", "b", "err", "rect", "outside", "tagId", "add", "currentIds", "ids", "result", "tags", "taskCard", "columnId", "fallbackName", "shell", "badge", "columnEl", "dotStyle", "_hex", "card", "s", "m", "h", "n", "x", "col", "id", "dot", "currentColumnId", "host", "options", "v", "assignedUsers", "members", "assignedIds", "u", "member", "checked", "avatar", "cb", "avatarContainer", "fields", "fieldValues", "field", "value", "rawValue", "labelBtn", "parsed", "persist", "opts", "kdd", "initial", "input", "display", "wrap", "renderEditing", "commit", "renderDisplay", "editRow", "link", "editBtn", "type", "iso", "d", "label", "o", "rawOptions", "c", "isSelect", "nameInput", "choicesEditor", "countEl", "cs", "newName", "choices", "popRect", "top", "picker", "found", "fieldId", "patch", "updated", "f", "currentValue", "fresh", "comments", "comment", "content", "delta", "numEl", "next", "title", "description", "el", "data", "titleEl", "descRaw", "desc", "descEl", "truncated", "targetContainer", "emptyState", "targetBoardId", "svgs", "catalog", "rows", "showOpts", "pretty", "fieldType", "text", "div", "BlockEditor", "content", "md", "lines", "blocks", "inCodeBlock", "codeContent", "codeLanguage", "i", "line", "meta", "mediaHandled", "sentinel", "prefix", "checked", "todoContent", "match", "blockEls", "serializeContent", "contentEl", "type", "blockEl", "num", "lang", "cap", "block", "index", "emptyBlock", "div", "addBtn", "e", "dragHandle", "mouseDownAt", "dx", "dy", "hr", "link", "wrapper", "checkbox", "menuItem", "menu", "slashIndex", "query", "blockLine", "selected", "blockType", "isEmpty", "newBlock", "target", "goingUp", "sibling", "prevBlock", "prevContent", "range", "sel", "direction", "items", "current", "currentIndex", "anchorRect", "margin", "w", "h", "left", "spaceBelow", "spaceAbove", "top", "anchorEl", "filterInput", "firstItem", "el", "lowerQuery", "firstVisible", "item", "label", "matches", "currentContent", "cleanContent", "newContent", "placeholder", "body", "res", "data", "linkBlock", "followUp", "err", "typeSlug", "ph", "fig", "img", "video", "audio", "sizeStr", "safeHref", "host", "initial", "bytes", "units", "n", "raw", "url", "input", "file", "c", "sourceBlockLine", "fd", "finalBlock", "s", "title", "indicator", "crumb", "error", "html", "bar", "btn", "cmd", "inner", "palette", "colorBtn", "hex", "fmtBtn", "a", "node", "rect", "on", "intersects", "parent", "action", "icon", "hint", "turnIntoTypes", "t", "empty", "focusTarget", "cb", "newType", "oldType", "tmp", "replacement", "_e", "midY", "isTopHalf", "relatedTarget", "caretRect", "elRect", "slack", "position", "number", "menu", "modal", "csrf", "active", "activeTriggerEl", "readContext", "trigger", "showToast", "msg", "kind", "existing", "toast", "accent", "openMenu", "iconEl", "titleEl", "favLbl", "positionMenu", "closeMenu", "rect", "menuRect", "margin", "left", "top", "e", "closeModal", "item", "doFavorite", "doCopyLink", "doDuplicate", "doRename", "openModal", "doOpenTab", "doDelete", "res", "data", "nowStarred", "starBtn", "ic", "err", "url", "ta", "input", "startInlineRename", "row", "link", "labelSpan", "currentTitle", "committed", "commit", "newTitle", "cancel", "backdrop", "closeBtn", "searchEl", "listEl", "emptyEl", "subjectEl", "countEl", "allRows", "invalidIds", "sidebarRow", "el", "visible", "id", "invalid", "refreshCount", "showAllGroups", "n", "l", "recomputeGroupVisibility", "label", "groupName", "anyVisible", "cssEscape", "shown", "r", "v", "q", "firstActive", "title", "proj", "matches", "disabled", "show", "visibleRows", "currentIdx", "next", "commitMove", "targetId", "targetTitle"] }