📜
attributes.js
Back
📝 Javascript ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
/* ---------- Object Overlay Management ---------- */ /* DOM Elements */ let attributesObjectViewBtn, objectOverlay, ovTitle, ovBody, closeOverlayBtn; /* ---------- Attribute Row Creation ---------- */ function makeAttrRow(scope, scopeId, idx, attr) { const row = document.createElement('div'); row.className = 'attr-row'; const keyInput = document.createElement('input'); keyInput.type = 'text'; keyInput.placeholder = 'Attribute name'; keyInput.className = 'attr-key'; keyInput.value = attr.key ?? ''; keyInput.dataset.scope = scope; keyInput.dataset.scopeId = scopeId; keyInput.dataset.index = String(idx); const valInput = document.createElement('input'); valInput.type = 'text'; valInput.placeholder = 'Value'; valInput.className = 'attr-val'; valInput.value = attr.value ?? ''; valInput.dataset.scope = scope; valInput.dataset.scopeId = scopeId; valInput.dataset.index = String(idx); const delBtn = document.createElement('button'); delBtn.textContent = '🗑️'; delBtn.title = 'Remove attribute'; delBtn.className = 'attr-del'; delBtn.dataset.scope = scope; delBtn.dataset.scopeId = scopeId; delBtn.dataset.index = String(idx); row.appendChild(keyInput); row.appendChild(valInput); row.appendChild(delBtn); return row; } /* ---------- Object Attributes Block ---------- */ function buildObjectAttributesBlock(obj) { const wrap = document.createElement('div'); wrap.className = 'ov-obj-attrs'; wrap.style.background = '#151515'; wrap.style.border = '1px solid #2a2a2a'; wrap.style.borderRadius = '.6rem'; wrap.style.padding = '.6rem'; wrap.style.marginBottom = '.8rem'; const head = document.createElement('div'); head.style.display = 'flex'; head.style.alignItems = 'center'; head.style.gap = '.6rem'; const title = document.createElement('h3'); title.textContent = 'Object Attributes'; title.style.margin = '.1rem 0'; title.style.color = '#ddd'; const addKey = document.createElement('input'); addKey.type = 'text'; addKey.placeholder = 'Attribute name'; addKey.id = 'ov-add-obj-key'; const addVal = document.createElement('input'); addVal.type = 'text'; addVal.placeholder = 'Value'; addVal.id = 'ov-add-obj-val'; const addBtn = document.createElement('button'); addBtn.textContent = '➕ Add'; addBtn.className = 'attr-add'; addBtn.dataset.scope = 'object'; addBtn.dataset.scopeId = obj.id; head.appendChild(title); head.appendChild(addKey); head.appendChild(addVal); head.appendChild(addBtn); const list = document.createElement('div'); list.className = 'attr-list'; list.dataset.scope = 'object'; list.dataset.scopeId = obj.id; for (let i = 0; i < (obj.attributes?.length || 0); i++) { list.appendChild(makeAttrRow('object', obj.id, i, obj.attributes[i])); } wrap.appendChild(head); wrap.appendChild(list); return wrap; } /* ---------- Line Block ---------- */ function buildLineBlock(line) { const block = document.createElement('div'); block.className = 'ov-line'; const h = document.createElement('h3'); h.textContent = line.name; const attrHead = document.createElement('div'); attrHead.style.display = 'flex'; attrHead.style.alignItems = 'center'; attrHead.style.gap = '.6rem'; attrHead.style.marginBottom = '.3rem'; const attrTitle = document.createElement('div'); attrTitle.textContent = 'Line Attributes'; attrTitle.style.color = '#bbb'; const addKey = document.createElement('input'); addKey.type = 'text'; addKey.placeholder = 'Attribute name'; addKey.className = 'ov-add-line-key'; addKey.dataset.lineId = line.id; const addVal = document.createElement('input'); addVal.type = 'text'; addVal.placeholder = 'Value'; addVal.className = 'ov-add-line-val'; addVal.dataset.lineId = line.id; const addBtn = document.createElement('button'); addBtn.textContent = '➕ Add'; addBtn.className = 'attr-add'; addBtn.dataset.scope = 'line'; addBtn.dataset.scopeId = line.id; attrHead.appendChild(attrTitle); attrHead.appendChild(addKey); attrHead.appendChild(addVal); attrHead.appendChild(addBtn); const list = document.createElement('div'); list.className = 'attr-list'; list.dataset.scope = 'line'; list.dataset.scopeId = line.id; for (let i = 0; i < (line.attributes?.length || 0); i++) { list.appendChild(makeAttrRow('line', line.id, i, line.attributes[i])); } const strip = document.createElement('div'); strip.className = 'ov-strip'; for (const t of (line.items || [])) { const item = document.createElement('div'); item.className = 'ov-item'; const img = document.createElement('img'); img.src = t.thumbDataURL; const badge = document.createElement('div'); badge.className = 'ov-badge'; badge.textContent = t.badge; item.appendChild(img); item.appendChild(badge); strip.appendChild(item); } block.appendChild(h); block.appendChild(attrHead); block.appendChild(list); block.appendChild(strip); return block; } /* ---------- Overlay Rendering ---------- */ function renderObjectOverlay() { const o = window.WorkspaceAPI.activeObject(); if(!o) return; ovTitle.textContent = o.name; ovBody.innerHTML = ''; ovBody.appendChild(buildObjectAttributesBlock(o)); for (const line of o.lines) { ovBody.appendChild(buildLineBlock(line)); } } /* ---------- Overlay Controls ---------- */ function openObjectView() { renderObjectOverlay(); objectOverlay.classList.add('open'); objectOverlay.setAttribute('aria-hidden', 'false'); } function closeObjectView() { objectOverlay.classList.remove('open'); objectOverlay.setAttribute('aria-hidden', 'true'); } /* ---------- Attribute Event Handlers ---------- */ function initAttributeEvents() { // Add/remove attribute handlers ovBody.addEventListener('click', (e) => { const btn = e.target.closest('.attr-add'); const del = e.target.closest('.attr-del'); if (btn) { const scope = btn.dataset.scope; const scopeId = btn.dataset.scopeId; if (scope === 'object') { const keyEl = document.getElementById('ov-add-obj-key'); const valEl = document.getElementById('ov-add-obj-val'); const key = (keyEl.value || '').trim(); const value = (valEl.value || '').trim(); if (!key) { keyEl.focus(); return; } const o = window.WorkspaceAPI.activeObject(); if(!o) return; o.attributes = o.attributes || []; o.attributes.push({key, value}); keyEl.value = ''; valEl.value = ''; renderObjectOverlay(); return; } if (scope === 'line') { const o = window.WorkspaceAPI.activeObject(); if(!o) return; const line = o.lines.find(l => l.id === scopeId); if(!line) return; const head = btn.parentElement; const keyEl = head.querySelector('.ov-add-line-key'); const valEl = head.querySelector('.ov-add-line-val'); const key = (keyEl?.value || '').trim(); const value = (valEl?.value || '').trim(); if (!key) { keyEl?.focus(); return; } line.attributes = line.attributes || []; line.attributes.push({key, value}); if (keyEl) keyEl.value = ''; if (valEl) valEl.value = ''; renderObjectOverlay(); return; } } if (del) { const scope = del.dataset.scope; const scopeId = del.dataset.scopeId; const idx = parseInt(del.dataset.index, 10); const o = window.WorkspaceAPI.activeObject(); if(!o) return; if (scope === 'object') { if (o.attributes && o.attributes[idx]) { o.attributes.splice(idx, 1); } renderObjectOverlay(); return; } if (scope === 'line') { const line = o.lines.find(l => l.id === scopeId); if (line && line.attributes && line.attributes[idx]) { line.attributes.splice(idx, 1); } renderObjectOverlay(); return; } } }); // Live editing of attributes ovBody.addEventListener('input', (e) => { const keyEl = e.target.closest('.attr-key'); const valEl = e.target.closest('.attr-val'); const o = window.WorkspaceAPI.activeObject(); if(!o) return; function apply(el, field) { const scope = el.dataset.scope; const scopeId = el.dataset.scopeId; const idx = parseInt(el.dataset.index, 10); if (scope === 'object') { if (!o.attributes || !o.attributes[idx]) return; o.attributes[idx][field] = el.value; } else if (scope === 'line') { const line = o.lines.find(l => l.id === scopeId); if (!line || !line.attributes || !line.attributes[idx]) return; line.attributes[idx][field] = el.value; } } if (keyEl) apply(keyEl, 'key'); if (valEl) apply(valEl, 'value'); }); } /* ---------- Initialization ---------- */ function initializeAttributes() { try { // Get DOM elements attributesObjectViewBtn = document.getElementById('objectViewBtn'); objectOverlay = document.getElementById('objectOverlay'); ovTitle = document.getElementById('ovTitle'); ovBody = document.getElementById('ovBody'); closeOverlayBtn = document.getElementById('closeOverlayBtn'); // Check required DOM elements and dependencies if (!attributesObjectViewBtn || !objectOverlay || !ovBody) { throw new Error('Required DOM elements not found'); } if (!window.WorkspaceAPI || typeof window.WorkspaceAPI.activeObject !== 'function') { throw new Error('WorkspaceAPI not available'); } // Set up event handlers attributesObjectViewBtn.addEventListener('click', openObjectView); closeOverlayBtn.addEventListener('click', closeObjectView); objectOverlay.addEventListener('click', (e) => { if(e.target === objectOverlay) closeObjectView(); }); initAttributeEvents(); } catch (error) { alert(`Attributes module failed to initialize: ${error.message}`); throw error; } } // Export API for other modules window.AttributesAPI = { renderObjectOverlay, openObjectView, closeObjectView };