(function () { 'use strict'; if (window.__nqsTalkEmbedInitialized) { return; } window.__nqsTalkEmbedInitialized = true; var path = String(window.location && window.location.pathname ? window.location.pathname : ''); var isTalkPath = /\/apps\/spreed(\/|$)/.test(path) || /^\/call\/[^/?#]+/i.test(path) || /^\/room\/[^/?#]+/i.test(path) || /^\/conversation\/[^/?#]+/i.test(path); if (!isTalkPath) { return; } var placementTimer = null; var activeToken = ''; var elements = buildUi(); function requestToken() { if (typeof OC !== 'undefined' && OC.requestToken) { return OC.requestToken; } var meta = document.querySelector('meta[name="requesttoken"]'); return meta && meta.content ? meta.content : ''; } function appUrl(pathPart) { if (typeof OC !== 'undefined' && typeof OC.generateUrl === 'function') { return OC.generateUrl('/apps/nuqloud_scrum' + pathPart); } return '/apps/nuqloud_scrum' + pathPart; } function parseJsonResponse(response) { return response.text().then(function (text) { var data = {}; if (text) { try { data = JSON.parse(text); } catch (_error) { data = {}; } } if (!response.ok || (data && data.ok === false)) { throw new Error((data && data.error) ? data.error : 'Request failed.'); } return data; }); } function getJson(url) { return fetch(url, { method: 'GET', credentials: 'same-origin', headers: { Accept: 'application/json', requesttoken: requestToken() } }).then(parseJsonResponse); } function postJson(url, payload) { return fetch(url, { method: 'POST', credentials: 'same-origin', headers: { Accept: 'application/json', 'Content-Type': 'application/json', requesttoken: requestToken() }, body: JSON.stringify(payload || {}) }).then(parseJsonResponse); } function extractConversationToken() { var currentPath = String(window.location && window.location.pathname ? window.location.pathname : ''); var hashPath = String(window.location && window.location.hash ? window.location.hash : ''); var patterns = [ /^\/call\/([^/?#]+)/i, /^\/room\/([^/?#]+)/i, /^\/conversation\/([^/?#]+)/i, /\/apps\/spreed\/call\/([^/?#]+)/i, /\/apps\/spreed\/room\/([^/?#]+)/i, /\/apps\/spreed\/conversation\/([^/?#]+)/i ]; for (var index = 0; index < patterns.length; index += 1) { var match = currentPath.match(patterns[index]); if (match && match[1]) { return decodeURIComponent(match[1]); } } for (var hashIndex = 0; hashIndex < patterns.length; hashIndex += 1) { var hashMatch = hashPath.match(patterns[hashIndex]); if (hashMatch && hashMatch[1]) { return decodeURIComponent(hashMatch[1]); } } var params = new URLSearchParams(window.location.search); var queryCandidates = ['conversationToken', 'conversation', 'token']; for (var keyIndex = 0; keyIndex < queryCandidates.length; keyIndex += 1) { var value = params.get(queryCandidates[keyIndex]); if (value && value.trim()) { return value.trim(); } } return ''; } function conversationNameFallback() { var title = String(document.title || '').replace(/\s+-\s+Nextcloud.*$/i, '').trim(); return title || activeToken; } function buildUi() { var section = document.createElement('details'); section.className = 'nqs-talk-settings-section'; section.open = true; var summary = document.createElement('summary'); summary.textContent = 'NuQloud Scrum'; var body = document.createElement('div'); body.className = 'nqs-talk-settings-body'; body.innerHTML = '' + '
Use this Talk channel as a Scrum project. Talk threads become tasks; Deck comments are the next mirror step.
' + '' + ''; section.appendChild(summary); section.appendChild(body); document.body.appendChild(section); return { section: section, status: body.querySelector('.nqs-talk-status'), toggle: body.querySelector('.nqs-talk-toggle') }; } function isVisibleNode(node) { if (!node || !node.isConnected || node.getAttribute('aria-hidden') === 'true') { return false; } try { var style = window.getComputedStyle(node); return style.display !== 'none' && style.visibility !== 'hidden'; } catch (_error) { return true; } } function findConversationSettingsHost() { var selectors = [ '[role="dialog"] [data-cy-conversation-settings]', '[aria-modal="true"] [data-cy-conversation-settings]', '.modal-container [data-cy-conversation-settings]', '.modal-wrapper [data-cy-conversation-settings]', '.nc-modal [data-cy-conversation-settings]', '.v--modal-box [data-cy-conversation-settings]', '[role="dialog"] [id*="conversation-settings"]', '[aria-modal="true"] [id*="conversation-settings"]', '[role="dialog"] [class*="conversation-settings"]', '[aria-modal="true"] [class*="conversation-settings"]' ]; for (var index = 0; index < selectors.length; index += 1) { var nodes = document.querySelectorAll(selectors[index]); for (var nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += 1) { if (isVisibleNode(nodes[nodeIndex])) { return nodes[nodeIndex]; } } } return null; } function setStatus(message, isError) { if (!elements.status) { return; } elements.status.textContent = message; elements.status.classList.toggle('nqs-talk-error', Boolean(isError)); } function renderStatus(status) { var enabled = Boolean(status && status.enabled); elements.toggle.textContent = enabled ? 'Disable Scrum' : 'Enable Scrum'; elements.toggle.dataset.enabled = enabled ? '1' : '0'; setStatus(enabled ? 'Scrum is enabled for this project.' : 'Scrum is disabled for this project.', false); } function loadStatus() { var token = extractConversationToken(); if (!token) { activeToken = ''; elements.toggle.disabled = true; setStatus('Open a Talk conversation to manage Scrum.', false); return Promise.resolve(); } activeToken = token; elements.toggle.disabled = true; setStatus('Loading Scrum status...', false); return getJson(appUrl('/api/conversations/' + encodeURIComponent(token) + '/scrum')) .then(function (result) { var data = result && result.data ? result.data : {}; renderStatus(data); }) .catch(function (error) { setStatus('Unable to load Scrum status for this conversation. ' + error.message, true); }) .finally(function () { elements.toggle.disabled = false; }); } function toggleScrum() { var token = activeToken || extractConversationToken(); if (!token) { setStatus('Open a Talk conversation to manage Scrum.', true); return; } var enabled = elements.toggle.dataset.enabled !== '1'; elements.toggle.disabled = true; setStatus(enabled ? 'Enabling Scrum...' : 'Disabling Scrum...', false); postJson(appUrl('/api/conversations/' + encodeURIComponent(token) + '/scrum'), { enabled: enabled, talkRoomName: conversationNameFallback() }).then(function (result) { var data = result && result.data ? result.data : {}; renderStatus(data); }).catch(function (error) { setStatus('Unable to update Scrum for this conversation. ' + error.message, true); }).finally(function () { elements.toggle.disabled = false; }); } function syncPlacement() { var host = findConversationSettingsHost(); if (!host) { if (elements.section.parentNode !== document.body) { document.body.appendChild(elements.section); } elements.section.classList.add('nqs-hidden'); return; } if (elements.section.parentNode !== host) { host.appendChild(elements.section); loadStatus(); } elements.section.classList.remove('nqs-hidden'); } elements.toggle.addEventListener('click', toggleScrum); placementTimer = window.setInterval(syncPlacement, 1100); document.addEventListener('click', function () { window.setTimeout(syncPlacement, 100); }, true); window.addEventListener('hashchange', loadStatus); window.addEventListener('popstate', loadStatus); syncPlacement(); }());