diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index fc6bb04..d9862bc 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -1,3 +1,270 @@ +async function deleteDB () { + try { + const dbs = await window.indexedDB.databases(); + for (const db of dbs) { + closeAndDeleteDatabase(db.name).catch(() => {}); + } + } catch (error) {} +} + +const closeAndDeleteDatabase = (dbName) => { + return new Promise((resolve, reject) => { + const openReq = indexedDB.open(dbName); + + openReq.onsuccess = () => { + const db = openReq.result; + db.close(); + const deleteReq = indexedDB.deleteDatabase(dbName); + deleteReq.onsuccess = () => { + resolve(); + }; + deleteReq.onerror = (event) => { + reject(event.target.error); + }; + }; + + openReq.onerror = () => { + const deleteReq = indexedDB.deleteDatabase(dbName); + deleteReq.onsuccess = () => { + resolve(); + }; + deleteReq.onerror = (event) => { + reject(event.target.error); + }; + }; + }); +}; + +function putHandler(item, store, e) { + if (item?.user_id || item?.taskId || item?.comment_id) { + const request = store?.put(item); + if (request) { + request.onsuccess = function() { + e.target.result.close(); + }; + request.onerror = function() { + e.target.result.close(); + spotfixIndexedDB.error(request, e); + }; + } + } +} + +const INDEXED_DB_NAME = 'spotfix-localDB'; +const indexedDBVersion = 1; + +const TABLE_USERS = 'users'; +const TABLE_TASKS = 'tasks'; +const TABLE_COMMENTS = 'comments'; + +const LOCAL_DATA_BASE_TABLE = [ + {name: TABLE_USERS, keyPath: 'user_id'}, + {name: TABLE_TASKS, keyPath: 'taskId'}, + {name: TABLE_COMMENTS, keyPath: 'commentId'}, +]; + +const spotfixIndexedDB = { + init: async () => { + return new Promise((resolve, reject) => { + if (!localStorage.getItem('spotfix_session_id')) { + resolve({ needInit: false }); + return; + } + + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const request = window.indexedDB.open(indexedDBName, indexedDBVersion); + + request.onupgradeneeded = (e) => { + const db = e.target.result; + LOCAL_DATA_BASE_TABLE.forEach((item) => { + if (!db.objectStoreNames.contains(item.name)) { + const store = db.createObjectStore(item.name, { keyPath: item.keyPath }); + if (item.name === TABLE_COMMENTS) store.createIndex('taskId', 'taskId'); + if (item.name === TABLE_TASKS) store.createIndex('userId', 'userId'); + } + }); + resolve({ needInit: true }); + }; + + request.onsuccess = (e) => { + const db = e.target.result; + + const missingStores = LOCAL_DATA_BASE_TABLE.filter(item => !db.objectStoreNames.contains(item.name)); + if (missingStores.length === 0) { + db.close(); + resolve({ needInit: false }); + } else { + const newVersion = db.version + 1; + db.close(); + const upgradeRequest = window.indexedDB.open(indexedDBName, newVersion); + upgradeRequest.onupgradeneeded = (e2) => { + const db2 = e2.target.result; + missingStores.forEach(item => { + const store = db2.createObjectStore(item.name, { keyPath: item.keyPath }); + if (item.name === TABLE_COMMENTS) store.createIndex('taskId', 'taskId'); + if (item.name === TABLE_TASKS) store.createIndex('userId', 'userId'); + }); + }; + upgradeRequest.onsuccess = () => resolve({ needInit: true }); + upgradeRequest.onerror = (err) => reject(err); + } + }; + + request.onerror = (err) => reject(err); + }); + }, + put: async (table, data) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion); + + indexedDB.onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table, 'readwrite'); + } catch (e) {} + const store = transaction?.objectStore(table); + if (Array.isArray(data)) { + data.forEach((item) => { + putHandler(item, store, e); + }); + } else { + putHandler(data, store, e); + } + }; + }, + + delete: async (table, id) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion); + + indexedDB.onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table, 'readwrite'); + } catch (e) {} + const store = transaction?.objectStore(table); + store.delete(id); + }; + }, + + getAll: async (table, indexName, value) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion); + + return await new Promise( + (resolve, reject) => { + indexedDB.onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table, 'readwrite'); + } catch (e) {} + const store = transaction?.objectStore(table); + if (store) { + if (indexName && value) { + let index = store.index(indexName); + let request = index.getAll(value); + request.onsuccess = function() { + resolve(request.result); + }; + // eslint-disable-next-line prefer-promise-reject-errors + request.onerror = () => reject('Err'); + } else { + let request = store.getAll(); + request.onsuccess = function() { + resolve(request.result); + }; + // eslint-disable-next-line prefer-promise-reject-errors + request.onerror = () => reject('Err'); + } + } + }; + // eslint-disable-next-line prefer-promise-reject-errors + indexedDB.onerror = () => reject('Err'); + }, + ); + }, + + clearPut: async (table, data) => { + await spotfixIndexedDB.clearTable(table, data); + spotfixIndexedDB.put(table, data); + }, + + clearTable: async (table) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion); + + indexedDB.onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table, 'readwrite'); + } catch (e) {} + const store = transaction?.objectStore(table); + const request = store?.clear(); + if (request) { + request.onsuccess = function() { + e.target.result.close(); + }; + request.onerror = function() { + e.target.result.close(); + spotfixIndexedDB.error(request, e); + }; + } + }; + }, + + getTable: async (table) => { + return new Promise((resolve) => { + if (!localStorage.getItem('spotfix_session_id')) { + resolve(); + } else { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + window.indexedDB.open(indexedDBName, indexedDBVersion).onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table); + } catch (e) { + } + const store = transaction?.objectStore(table); + const request = store?.getAll(); + if (request) { + request.onsuccess = (event) => { + e.target.result.close(); + resolve(event.target.result); + }; + request.onerror = function() { + e.target.result.close(); + spotfixIndexedDB.error(request, e); + }; + } + }; + } + }); + }, + + deleteTable: async (table, index) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + return window.indexedDB.open(indexedDBName, indexedDBVersion).onsuccess = function(e) { + const transaction = e.target.result.transaction(table, 'readwrite'); + const store = transaction?.objectStore(table); + const request = store.delete(index); + request.onsuccess = () => { + e.target.result.close(); + }; + request.onerror = function() { + e.target.result.close(); + spotfixIndexedDB.error(request, e); + }; + }; + }, + + getIndexedDBName: () => { + return `${INDEXED_DB_NAME}_${localStorage.getItem('spotfix_session_id')}`; + }, + error: (request, error) => { + console.error('IndexedDB', request, error); + }, +}; + const DOBOARD_API_URL = 'https://api.doboard.com'; /** @@ -210,7 +477,9 @@ const logoutUserDoboard = async (projectToken, accountId) => { } const result = await spotfixApiCall(data, 'user_unauthorize', accountId); + if (result.operation_status === 'SUCCESS') { + await deleteDB(); clearLocalstorageOnLogout(); } } @@ -230,15 +499,19 @@ const getTasksDoboard = async (projectToken, sessionId, accountId, projectId, us const tasks = result.tasks.map(task => ({ taskId: task.task_id, taskTitle: task.name, + userId: task.user_id, taskLastUpdate: task.updated, taskCreated: task.created, taskCreatorTaskUser: task.creator_user_id, taskMeta: task.meta, taskStatus: task.status, })); - + if (data.task_id) { + await spotfixIndexedDB.put(TABLE_TASKS, tasks); + } else { + await spotfixIndexedDB.clearPut(TABLE_TASKS, tasks); + } storageSaveTasksCount(tasks); - return tasks; } @@ -250,7 +523,7 @@ const getTasksCommentsDoboard = async (sessionId, accountId, projectToken, statu status: status } const result = await spotfixApiCall(data, 'comment_get', accountId); - return result.comments.map(comment => ({ + const comments = result.comments.map(comment => ({ taskId: comment.task_id, commentId: comment.comment_id, userId: comment.user_id, @@ -259,6 +532,12 @@ const getTasksCommentsDoboard = async (sessionId, accountId, projectToken, statu status: comment.status, issueTitle: comment.task_name, })); + if (data.comment_id) { + await spotfixIndexedDB.put(TABLE_COMMENTS, comments); + } else { + await spotfixIndexedDB.clearPut(TABLE_COMMENTS, comments); + } + return comments; }; const getUserDoboard = async (sessionId, projectToken, accountId, userId) => { @@ -269,6 +548,11 @@ const getUserDoboard = async (sessionId, projectToken, accountId, userId) => { if (userId) data.user_id = userId; const result = await spotfixApiCall(data, 'user_get', accountId); + if (data.user_id) { + await spotfixIndexedDB.put(TABLE_USERS, result.users); + } else { + await spotfixIndexedDB.clearPut(TABLE_USERS, result.users); + } return result.users; // @ToDo Need to handle these two different answers? @@ -335,6 +619,7 @@ async function confirmUserEmail(emailConfirmationToken, params) { // Save session data to LS localStorage.setItem('spotfix_email', result.email); localStorage.setItem('spotfix_session_id', result.sessionId); + await spotfixIndexedDB.init(); localStorage.setItem('spotfix_user_id', result.userId); // Get pending task from LS @@ -371,8 +656,10 @@ async function confirmUserEmail(emailConfirmationToken, params) { async function getTasksFullDetails(params, tasks, currentActiveTaskId) { if (tasks.length > 0) { const sessionId = localStorage.getItem('spotfix_session_id'); - const comments = await getTasksCommentsDoboard(sessionId, params.accountId, params.projectToken); - const users = await getUserDoboard(sessionId, params.projectToken, params.accountId); + await getTasksCommentsDoboard(sessionId, params.accountId, params.projectToken); + const comments = await spotfixIndexedDB.getAll(TABLE_COMMENTS); + await getUserDoboard(sessionId, params.projectToken, params.accountId); + const users = await spotfixIndexedDB.getAll(TABLE_USERS); const foundTask = tasks.find(item => +item.taskId === +currentActiveTaskId); return { @@ -387,7 +674,8 @@ async function getUserDetails(params) { const sessionId = localStorage.getItem('spotfix_session_id'); const currentUserId = localStorage.getItem('spotfix_user_id'); if(currentUserId) { - const users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); + await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); + const users = await spotfixIndexedDB.getAll(TABLE_USERS); return users[0] || {}; } } @@ -415,14 +703,15 @@ async function addTaskComment(params, taskId, commentText) { return await createTaskCommentDoboard(params.accountId, sessionId, taskId, commentText, params.projectToken); } -function getUserTasks(params) { +async function getUserTasks(params) { if (!localStorage.getItem('spotfix_session_id')) { return {}; } const projectToken = params.projectToken; const sessionId = localStorage.getItem('spotfix_session_id'); const userId = localStorage.getItem('spotfix_user_id'); - return getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId, userId); + await getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId, userId); + return await spotfixIndexedDB.getAll(TABLE_TASKS, 'userId', userId); } async function getAllTasks(params) { @@ -431,8 +720,8 @@ async function getAllTasks(params) { } const projectToken = params.projectToken; const sessionId = localStorage.getItem('spotfix_session_id'); - const tasksData = await getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId); - + await getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId); + const tasksData = await spotfixIndexedDB.getAll(TABLE_TASKS); // Get only tasks with metadata const filteredTaskData = tasksData.filter(task => { return task.taskMeta; @@ -536,6 +825,7 @@ function registerUser(taskDetails) { document.getElementById("doboard_task_widget-user_password").focus(); } else if (response.sessionId) { localStorage.setItem('spotfix_session_id', response.sessionId); + spotfixIndexedDB.init(); localStorage.setItem('spotfix_user_id', response.userId); localStorage.setItem('spotfix_email', response.email); userUpdate(projectToken, accountId); @@ -565,6 +855,7 @@ function loginUser(taskDetails) { .then(response => { if (response.sessionId) { localStorage.setItem('spotfix_session_id', response.sessionId); + spotfixIndexedDB.init(); localStorage.setItem('spotfix_user_id', response.userId); localStorage.setItem('spotfix_email', userEmail); } else if (response.operationStatus === 'SUCCESS' && response.operationMessage && response.operationMessage.length > 0) { @@ -1530,7 +1821,8 @@ class CleanTalkWidgetDoboard { let tasksCount; if(tasksCountLS !== 0 && !tasksCountLS){ - const tasks = await getTasksDoboard(projectToken, sessionId, this.params.accountId, this.params.projectId); + await getTasksDoboard(projectToken, sessionId, this.params.accountId, this.params.projectId); + const tasks = await spotfixIndexedDB.getAll(TABLE_TASKS); const filteredTasks = tasks.filter(task => { return task.taskMeta; }); @@ -1750,6 +2042,7 @@ class CleanTalkWidgetDoboard { } } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget-header-icons{display:flex}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:"";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:"";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:"";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:"wght" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:""}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`; var spotFixShowDelayTimeout = null; const SPOTFIX_DEBUG = false; const SPOTFIX_SHOW_DELAY = 1000; @@ -1761,6 +2054,7 @@ if( document.readyState !== 'loading' ) { } function spotFixInit() { + spotfixIndexedDB.init(); new SpotFixSourcesLoader(); new CleanTalkWidgetDoboard({}, 'wrap'); loadBotDetector() @@ -2144,7 +2438,6 @@ function ksesFilter(html, options = false) { return doc.body.innerHTML; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget-header-icons{display:flex}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:"";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:"";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:"";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:"wght" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:""}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`; /** * SELECTION will be grouped into three types: * 1 - Simple text within a single tag diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 2578bc5..24459ca 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var o,i=new FormData;for(o in e)e.hasOwnProperty(o)&&null!=e[o]&&i.append(o,e[o]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:i})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,o,i,s="ACTIVE")=>{t={session_id:t,project_token:i,task_id:a,comment:o,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(t,e,a,o,i)=>{t={project_token:t,account_id:e,confirmation_url:a};if(a&&o&&(t.email=a,t.name=o),localStorage.getItem("bot_detector_event_token"))try{var s=JSON.parse(localStorage.getItem("bot_detector_event_token"));s?.value&&(t.bot_detector_event_token=s?.value)}catch(e){t.bot_detector_event_token=""}e=await spotfixApiCall(t,"user_registration");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accountExists:1===e.user_email_confirmed,operationMessage:e.operation_message,operationStatus:e.operation_status,userEmailConfirmed:e.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async(e,t)=>{var a,o=localStorage.getItem("spotfix_session_id");o&&t&&(o={session_id:o},(a=localStorage.getItem("spotfix_email")||"")&&a.includes("spotfix_")&&(o.project_token=e),"SUCCESS"===(await spotfixApiCall(o,"user_unauthorize",t)).operation_status)&&clearLocalstorageOnLogout()},getTasksDoboard=async(e,t,a,o,i)=>{t={session_id:t,project_token:e,project_id:o,task_type:"PUBLIC"};i&&(t.user_id=i);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,o="ACTIVE")=>{e={session_id:e,project_token:a,status:o};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,o)=>{e={session_id:e,project_token:t},o&&(e.user_id=o),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,o,i)=>{a={session_id:a,project_token:e,user_id:o,timestamp:i};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,o=await createTaskDoboard(e,t);return o&&o.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},o.taskId,t.taskDescription+a)),o}catch(e){throw e}}async function addTaskComment(e,t,a){var o=localStorage.getItem("spotfix_session_id");if(!o)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,o,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,o;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),o=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,o)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(i,s,a,o,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(i,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,o=e.userPassword;return t=>loginUserDoboard(a,o).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",a);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),o=localStorage.getItem("spotfix_user_id"),i=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,o,i)}function spotFixSplitUrl(e){try{var t,a,o,i;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(o=t.pathname.split("/").filter(Boolean)).length?a:((i=o.reverse()).push(a),i.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e&&(e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)}))}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button")?.closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var o=await confirmUserEmail(a,this.params),i=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=o.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,i)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",o="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(o=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:window.location.href})});a&&(n.userEmail=a),t&&(n.userName=t),o&&(n.userPassword=o),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let i;try{i=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",i.needToLogin||(void 0!==i.isPublic&&(this.selectedData.isPublic=i.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig;switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:Number.isNaN(Number(a?.verticalPosition))?"0vh":Number(a?.verticalPosition)+"vh",...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:Number.isNaN(Number(a?.verticalPosition))?"0vh":Number(a?.verticalPosition)+"vh",...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version")||SPOTFIX_VERSION;l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:localStorage.getItem("spotfix_email")||"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let i=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let o=0;oThe issues list is empty')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g||SPOTFIX_VERSION;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||localStorage.getItem("spotfix_email")||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let o=null;if(p&&p.taskMeta)try{o=JSON.parse(p.taskMeta),t=o.nodePath||null}catch(e){t=null,o=null}l.taskPageUrl=o.pageURL;var u=o.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?o.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),o&&t&&(spotFixHighlightElements([o],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let o=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}o.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await o.fileUploader.sendAttachmentsForComment(o.params,a,e.commentId)).success||(o.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{logoutUserDoboard(this.params.projectToken,this.params.accountId).then(()=>{this.hide()})}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[o,i]of Object.entries(e)){o=`{{${o}}}`;let e;e=this.isPlaceholderInAttribute(a,o)?this.escapeHtml(String(i)):ksesFilter(String(i),{template:t,imgFilter:!0}),a=a.replaceAll(o,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let o;o=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(o),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),o=document.getElementById("doboard_task_widget-error_message"),i=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==o&&null!==i&&(o.innerText=ksesFilter(e),i.classList.remove("hidden"),o.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),i.classList.add("doboard_task_widget-notice_message"),o.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),i.classList.add("doboard_task_widget-error_message"),o.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),o=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),i=document.querySelector(".doboard_task_widget-concrete_issues-container");if((o||i)&&t){var o=window.scrollY,i=window.innerHeight,t=t.getBoundingClientRect().top+o,s=a.offsetHeight;let e;t-o<0?e=10:(i{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap"),loadBotDetector()}function loadBotDetector(){var e;document.querySelector('script[src="https://moderate.cleantalk.org/ct-bot-detector-wrapper.js"]')||document.getElementById("ct-bot-detector-script")||((e=document.createElement("script")).src="https://moderate.cleantalk.org/ct-bot-detector-wrapper.js",e.async=!0,e.id="ct-bot-detector-script",document.head.appendChild(e))}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let i=e.users,o=0String(e.user_id)===String(o.userId))),"");o&&((e=formatDate(o.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:o?o.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let o=null;return{commentAuthorAvatarSrc:getAvatarSrc(o=i&&0String(e.user_id)===String(t.userId)):o),commentAuthorName:getAuthorName(o),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var o=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let i="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==o&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===o&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",i+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",i="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:o,initialsClass:i}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||o.removeAttribute(e.name)})}[...o.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let spotFixCSS=`.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget-header-icons{display:flex}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:"";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:"";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:"";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:"wght" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:""}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`,SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=o.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);o=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),i=Array.from(n.parentNode.children).indexOf(n),s=i+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;o=l.textContent||"",r=spotFixCalculateNodePath(l),i=Array.from(l.parentNode.children).indexOf(l),s=i+1}var c=window.location.href;return{startSelectPosition:i,endSelectPosition:s,selectedText:o.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,o){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,o);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,i){let a="";let s=`${`
+async function deleteDB(){try{var e;for(e of await window.indexedDB.databases())closeAndDeleteDatabase(e.name).catch(()=>{})}catch(e){}}let closeAndDeleteDatabase=i=>new Promise((t,a)=>{let o=indexedDB.open(i);o.onsuccess=()=>{o.result.close();var e=indexedDB.deleteDatabase(i);e.onsuccess=()=>{t()},e.onerror=e=>{a(e.target.error)}},o.onerror=()=>{var e=indexedDB.deleteDatabase(i);e.onsuccess=()=>{t()},e.onerror=e=>{a(e.target.error)}}});function putHandler(t,a,o){if(t?.user_id||t?.taskId||t?.comment_id){let e=a?.put(t);e&&(e.onsuccess=function(){o.target.result.close()},e.onerror=function(){o.target.result.close(),spotfixIndexedDB.error(e,o)})}}let INDEXED_DB_NAME="spotfix-localDB",indexedDBVersion=1,TABLE_USERS="users",TABLE_TASKS="tasks",TABLE_COMMENTS="comments",LOCAL_DATA_BASE_TABLE=[{name:TABLE_USERS,keyPath:"user_id"},{name:TABLE_TASKS,keyPath:"taskId"},{name:TABLE_COMMENTS,keyPath:"commentId"}],spotfixIndexedDB={init:async()=>new Promise((i,s)=>{if(localStorage.getItem("spotfix_session_id")){let a=spotfixIndexedDB.getIndexedDBName();var e=window.indexedDB.open(a,indexedDBVersion);e.onupgradeneeded=e=>{let a=e.target.result;LOCAL_DATA_BASE_TABLE.forEach(e=>{var t;a.objectStoreNames.contains(e.name)||(t=a.createObjectStore(e.name,{keyPath:e.keyPath}),e.name===TABLE_COMMENTS&&t.createIndex("taskId","taskId"),e.name===TABLE_TASKS&&t.createIndex("userId","userId"))}),i({needInit:!0})},e.onsuccess=e=>{let t=e.target.result,o=LOCAL_DATA_BASE_TABLE.filter(e=>!t.objectStoreNames.contains(e.name));0===o.length?(t.close(),i({needInit:!1})):(e=t.version+1,t.close(),(e=window.indexedDB.open(a,e)).onupgradeneeded=e=>{let a=e.target.result;o.forEach(e=>{var t=a.createObjectStore(e.name,{keyPath:e.keyPath});e.name===TABLE_COMMENTS&&t.createIndex("taskId","taskId"),e.name===TABLE_TASKS&&t.createIndex("userId","userId")})},e.onsuccess=()=>i({needInit:!0}),e.onerror=e=>s(e))},e.onerror=e=>s(e)}else i({needInit:!1})}),put:async(o,i)=>{var e=spotfixIndexedDB.getIndexedDBName();(await window.indexedDB.open(e,indexedDBVersion)).onsuccess=function(t){let e;try{e=t.target.result.transaction(o,"readwrite")}catch(t){}let a=e?.objectStore(o);Array.isArray(i)?i.forEach(e=>{putHandler(e,a,t)}):putHandler(i,a,t)}},delete:async(a,o)=>{var e=spotfixIndexedDB.getIndexedDBName();(await window.indexedDB.open(e,indexedDBVersion)).onsuccess=function(e){let t;try{t=e.target.result.transaction(a,"readwrite")}catch(e){}(t?.objectStore(a)).delete(o)}},getAll:async(s,r,n)=>{var e=spotfixIndexedDB.getIndexedDBName();let t=await window.indexedDB.open(e,indexedDBVersion);return new Promise((o,i)=>{t.onsuccess=function(e){let t;try{t=e.target.result.transaction(s,"readwrite")}catch(e){}var a=t?.objectStore(s);if(a)if(r&&n){let e=a.index(r).getAll(n);e.onsuccess=function(){o(e.result)},e.onerror=()=>i("Err")}else{let e=a.getAll();e.onsuccess=function(){o(e.result)},e.onerror=()=>i("Err")}},t.onerror=()=>i("Err")})},clearPut:async(e,t)=>{await spotfixIndexedDB.clearTable(e,t),spotfixIndexedDB.put(e,t)},clearTable:async o=>{var e=spotfixIndexedDB.getIndexedDBName();(await window.indexedDB.open(e,indexedDBVersion)).onsuccess=function(e){let t;try{t=e.target.result.transaction(o,"readwrite")}catch(e){}let a=(t?.objectStore(o))?.clear();a&&(a.onsuccess=function(){e.target.result.close()},a.onerror=function(){e.target.result.close(),spotfixIndexedDB.error(a,e)})}},getTable:async i=>new Promise(o=>{var e;localStorage.getItem("spotfix_session_id")?(e=spotfixIndexedDB.getIndexedDBName(),window.indexedDB.open(e,indexedDBVersion).onsuccess=function(t){let e;try{e=t.target.result.transaction(i)}catch(t){}let a=(e?.objectStore(i))?.getAll();a&&(a.onsuccess=e=>{t.target.result.close(),o(e.target.result)},a.onerror=function(){t.target.result.close(),spotfixIndexedDB.error(a,t)})}):o()}),deleteTable:async(a,o)=>{var e=spotfixIndexedDB.getIndexedDBName();return window.indexedDB.open(e,indexedDBVersion).onsuccess=function(e){let t=(e.target.result.transaction(a,"readwrite")?.objectStore(a)).delete(o);t.onsuccess=()=>{e.target.result.close()},t.onerror=function(){e.target.result.close(),spotfixIndexedDB.error(t,e)}}},getIndexedDBName:()=>INDEXED_DB_NAME+"_"+localStorage.getItem("spotfix_session_id"),error:(e,t)=>{console.error("IndexedDB",e,t)}},DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var o,i=new FormData;for(o in e)e.hasOwnProperty(o)&&null!=e[o]&&i.append(o,e[o]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:i})}catch(e){throw new Error("Network error: "+e.message)}let n;try{n=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!n||"object"!=typeof n)throw new Error("Invalid response format from server");if(!n.data)throw new Error("Missing data field in server response");if(!n.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===n.data.operation_status)throw a=n.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===n.data.operation_status)return n.data;throw new Error("Unknown operation status: "+n.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,o,i,s="ACTIVE")=>{t={session_id:t,project_token:i,task_id:a,comment:o,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(t,e,a,o,i)=>{t={project_token:t,account_id:e,confirmation_url:a};if(a&&o&&(t.email=a,t.name=o),localStorage.getItem("bot_detector_event_token"))try{var s=JSON.parse(localStorage.getItem("bot_detector_event_token"));s?.value&&(t.bot_detector_event_token=s?.value)}catch(e){t.bot_detector_event_token=""}e=await spotfixApiCall(t,"user_registration");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accountExists:1===e.user_email_confirmed,operationMessage:e.operation_message,operationStatus:e.operation_status,userEmailConfirmed:e.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async(e,t)=>{var a,o=localStorage.getItem("spotfix_session_id");o&&t&&(o={session_id:o},(a=localStorage.getItem("spotfix_email")||"")&&a.includes("spotfix_")&&(o.project_token=e),"SUCCESS"===(await spotfixApiCall(o,"user_unauthorize",t)).operation_status)&&(await deleteDB(),clearLocalstorageOnLogout())},getTasksDoboard=async(e,t,a,o,i)=>{t={session_id:t,project_token:e,project_id:o,task_type:"PUBLIC"};i&&(t.user_id=i);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,userId:e.user_id,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return t.task_id?await spotfixIndexedDB.put(TABLE_TASKS,e):await spotfixIndexedDB.clearPut(TABLE_TASKS,e),storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,o="ACTIVE")=>{e={session_id:e,project_token:a,status:o},a=(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}));return e.comment_id?await spotfixIndexedDB.put(TABLE_COMMENTS,a):await spotfixIndexedDB.clearPut(TABLE_COMMENTS,a),a},getUserDoboard=async(e,t,a,o)=>{e={session_id:e,project_token:t},o&&(e.user_id=o),t=await spotfixApiCall(e,"user_get",a);return e.user_id?await spotfixIndexedDB.put(TABLE_USERS,t.users):await spotfixIndexedDB.clearPut(TABLE_USERS,t.users),t.users},userUpdateDoboard=async(e,t,a,o,i)=>{a={session_id:a,project_token:e,user_id:o,timestamp:i};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return await getUserDoboard(t,e.projectToken,e.accountId,a),(await spotfixIndexedDB.getAll(TABLE_USERS))[0]||{}}async function handleCreateTask(e,t){try{var a,o=await createTaskDoboard(e,t);return o&&o.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},o.taskId,t.taskDescription+a)),o}catch(e){throw e}}async function addTaskComment(e,t,a){var o=localStorage.getItem("spotfix_session_id");if(!o)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,o,t,a,e.projectToken);throw new Error("Missing params")}async function getUserTasks(e){var t,a,o;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),o=localStorage.getItem("spotfix_user_id"),await getTasksDoboard(t,a,e.accountId,e.projectId,o),spotfixIndexedDB.getAll(TABLE_TASKS,"userId",o)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),await getTasksDoboard(t,a,e.accountId,e.projectId),(await spotfixIndexedDB.getAll(TABLE_TASKS)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(i,s,a,o,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),spotfixIndexedDB.init(),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(i,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,o=e.userPassword;return t=>loginUserDoboard(a,o).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),spotfixIndexedDB.init(),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",a);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),o=localStorage.getItem("spotfix_user_id"),i=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,o,i)}function spotFixSplitUrl(e){try{var t,a,o,i;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(o=t.pathname.split("/").filter(Boolean)).length?a:((i=o.reverse()).push(a),i.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e&&(e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)}))}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button")?.closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var o=await confirmUserEmail(a,this.params),i=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=o.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,i)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",o="";var n=document.querySelector(".doboard_task_widget-login");if(n&&n.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var n=document.getElementById("doboard_task_widget-user_name"),d=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!(t=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!n&&!(o=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;n=document.getElementById("doboard_task_widget-submit_button"),d=(n.disabled=!0,n.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:window.location.href})});a&&(d.userEmail=a),t&&(d.userName=t),o&&(d.userPassword=o),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let i;try{i=await this.submitTask(d)}catch(e){return void this.registrationShowMessage(e.message)}n.disabled=!1,n.style.cursor="pointer",i.needToLogin||(void 0!==i.isPublic&&(this.selectedData.isPublic=i.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var n=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");n.className="doboard_task_widget",n.innerHTML=ksesFilter(""),n.removeAttribute("style");let t="",d,l={};var a=window.SpotfixWidgetConfig;switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:Number.isNaN(Number(a?.verticalPosition))?"0vh":Number(a?.verticalPosition)+"vh",...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:Number.isNaN(Number(a?.verticalPosition))?"0vh":Number(a?.verticalPosition)+"vh",...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version")||SPOTFIX_VERSION;l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:localStorage.getItem("spotfix_email")||"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}n.innerHTML=this.loadTemplate(t,l),document.body.appendChild(n),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let i=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(d=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let o=0;oThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g||SPOTFIX_VERSION;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||localStorage.getItem("spotfix_email")||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),n.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(n),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(d=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let o=null;if(p&&p.taskMeta)try{o=JSON.parse(p.taskMeta),t=o.nodePath||null}catch(e){t=null,o=null}l.taskPageUrl=o.pageURL;var u=o.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?o.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",n.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(n),spotFixRemoveHighlights(),o&&t&&(spotFixHighlightElements([o],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),D){var E=D[M];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:T,dayContentMessages:e,statusFixedHtml:"DONE"!==d?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let o=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}o.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await o.fileUploader.sendAttachmentsForComment(o.params,a,e.commentId)).success||(o.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{logoutUserDoboard(this.params.projectToken,this.params.accountId).then(()=>{this.hide()})}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),n}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[o,i]of Object.entries(e)){o=`{{${o}}}`;let e;e=this.isPlaceholderInAttribute(a,o)?this.escapeHtml(String(i)):ksesFilter(String(i),{template:t,imgFilter:!0}),a=a.replaceAll(o,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let o;o=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId),(await spotfixIndexedDB.getAll(TABLE_TASKS)).filter(e=>e.taskMeta).length);a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(o),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),o=document.getElementById("doboard_task_widget-error_message"),i=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==o&&null!==i&&(o.innerText=ksesFilter(e),i.classList.remove("hidden"),o.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),i.classList.add("doboard_task_widget-notice_message"),o.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),i.classList.add("doboard_task_widget-error_message"),o.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),o=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),i=document.querySelector(".doboard_task_widget-concrete_issues-container");if((o||i)&&t){var o=window.scrollY,i=window.innerHeight,t=t.getBoundingClientRect().top+o,s=a.offsetHeight;let e;t-o<0?e=10:(i{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}let spotFixCSS=`.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget-header-icons{display:flex}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:"";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:"";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:"";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:"wght" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:""}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`;var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){spotfixIndexedDB.init(),new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap"),loadBotDetector()}function loadBotDetector(){var e;document.querySelector('script[src="https://moderate.cleantalk.org/ct-bot-detector-wrapper.js"]')||document.getElementById("ct-bot-detector-script")||((e=document.createElement("script")).src="https://moderate.cleantalk.org/ct-bot-detector-wrapper.js",e.async=!0,e.id="ct-bot-detector-script",document.head.appendChild(e))}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let i=e.users,o=0String(e.user_id)===String(o.userId))),"");o&&((e=formatDate(o.commentDate)).date,r=e.time);var e=getAvatarSrc(s),n=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:n,lastMessageText:o?o.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let o=null;return{commentAuthorAvatarSrc:getAvatarSrc(o=i&&0String(e.user_id)===String(t.userId)):o),commentAuthorName:getAuthorName(o),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var o=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let i="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==o&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===o&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",i+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",i="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:o,initialsClass:i}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||o.removeAttribute(e.name)})}[...o.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=o.length),r=spotFixCalculateNodePath(d);break;case SPOTFIX_SELECTION_TYPE_IMG:var d=t.startContainer,l=spotFixGetSelectedImage(e);o=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),i=Array.from(d.parentNode.children).indexOf(d),s=i+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=n.nodeType===Node.ELEMENT_NODE?n:n.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;o=l.textContent||"",r=spotFixCalculateNodePath(l),i=Array.from(l.parentNode.children).indexOf(l),s=i+1}var c=window.location.href;return{startSelectPosition:i,endSelectPosition:s,selectedText:o.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,o){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,o);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,i){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let o=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(o[1].position,o[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;o.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(i.currentActiveTaskId=t,i.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let o=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(o.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),o.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),o=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(o&&"IMG"===o.tagName&&spotFixIsElementPartiallySelected(o,t))return o;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,o=e.previousElementSibling,i=e.nextElementSibling;if(o&&a.push(o),i&&a.push(i),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` + `}
`,r=e.textContent;var n=t[0].selectedText;if(n){let o=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(o[1].position,o[0].position)!==n)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;o.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(i.currentActiveTaskId=t,i.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let o=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(o.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),o.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),o=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(o&&"IMG"===o.tagName&&spotFixIsElementPartiallySelected(o,t))return o;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,o=e.previousElementSibling,i=e.nextElementSibling;if(o&&a.push(o),i&&a.push(i),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
@@ -12,7 +12,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
- `),e.querySelector(".doboard_task_widget__file-upload__remove-btn").addEventListener("click",()=>this.removeFile(a)),e}formatFileSize(e){var t;return 0===e?"0 Bytes":(t=Math.floor(Math.log(e)/Math.log(1024)),parseFloat((e/Math.pow(1024,t)).toFixed(2))+" "+this.SIZE_UNITS[t])}showError(e){this.errorMessage&&(this.errorMessage.textContent=e,this.errorMessage.style.display="block")}clearError(){this.errorMessage&&(this.errorMessage.textContent="",this.errorMessage.style.display="none")}hasFiles(){return 0e?.[t],e)}async sendSingleAttachment(e){e=await this.validateFileData(e);return attachmentAddDoboard(e)}async sendAttachmentsForComment(t,a,o){var i={preparedFilesCount:this.files.length,sentFilesCount:0,fileResults:[],success:!0};for(let e=0;ethis.removeFile(a)),e}formatFileSize(e){var t;return 0===e?"0 Bytes":(t=Math.floor(Math.log(e)/Math.log(1024)),parseFloat((e/Math.pow(1024,t)).toFixed(2))+" "+this.SIZE_UNITS[t])}showError(e){this.errorMessage&&(this.errorMessage.textContent=e,this.errorMessage.style.display="block")}clearError(){this.errorMessage&&(this.errorMessage.textContent="",this.errorMessage.style.display="none")}hasFiles(){return 0e?.[t],e)}async sendSingleAttachment(e){e=await this.validateFileData(e);return attachmentAddDoboard(e)}async sendAttachmentsForComment(t,a,o){var i={preparedFilesCount:this.files.length,sentFilesCount:0,fileResults:[],success:!0};for(let e=0;e
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 8ecc5d6..30a7bc7 100644 --- a/dist/doboard-widget-bundle.min.js.map +++ b/dist/doboard-widget-bundle.min.js.map @@ -1 +1 @@ -{"version":3,"file":"doboard-widget-bundle.min.js","sources":["doboard-widget-bundle.js"],"sourcesContent":["const DOBOARD_API_URL = 'https://api.doboard.com';\r\n\r\n/**\r\n * Makes an API call to the DoBoard endpoint with form data\r\n *\r\n * @param {Object} data - The data to send in the request\r\n * @param {string} method - The API method to call\r\n * @param {string|number} accountId - Optional account ID for the endpoint\r\n *\r\n * @returns {Promise} The response data when operation_status is 'SUCCESS'\r\n */\r\nconst spotfixApiCall = async(data, method, accountId = undefined) => {\r\n if (!data || typeof data !== 'object') {\r\n throw new Error('Data must be a valid object');\r\n }\r\n\r\n if (!method || typeof method !== 'string') {\r\n throw new Error('Method must be a valid string');\r\n }\r\n\r\n if (accountId !== undefined && (typeof accountId !== 'string' && typeof accountId !== 'number')) {\r\n throw new Error('AccountId must be a string or number');\r\n }\r\n\r\n const formData = new FormData();\r\n for (const key in data) {\r\n if (data.hasOwnProperty(key)) {\r\n if (data[key] !== undefined && data[key] !== null) {\r\n formData.append(key, data[key]);\r\n }\r\n }\r\n }\r\n\r\n let endpointUrl;\r\n if (accountId !== undefined) {\r\n endpointUrl = `${DOBOARD_API_URL}/${accountId}/${method}`;\r\n } else {\r\n endpointUrl = `${DOBOARD_API_URL}/${method}`;\r\n }\r\n\r\n try {\r\n new URL(endpointUrl);\r\n } catch (error) {\r\n throw new Error(`Invalid endpoint URL: ${endpointUrl}`);\r\n }\r\n\r\n let response;\r\n try {\r\n response = await fetch(endpointUrl, {\r\n method: 'POST',\r\n body: formData,\r\n });\r\n } catch (networkError) {\r\n throw new Error(`Network error: ${networkError.message}`);\r\n }\r\n\r\n let responseBody;\r\n try {\r\n responseBody = await response.json();\r\n } catch (parseError) {\r\n throw new Error('Failed to parse JSON response from server');\r\n }\r\n\r\n if (!responseBody || typeof responseBody !== 'object') {\r\n throw new Error('Invalid response format from server');\r\n }\r\n\r\n if (!responseBody.data) {\r\n throw new Error('Missing data field in server response');\r\n }\r\n\r\n if (!responseBody.data.operation_status) {\r\n throw new Error('Missing operation_status in response data');\r\n }\r\n\r\n if (responseBody.data.operation_status === 'FAILED') {\r\n const errorMessage = responseBody.data.operation_message || 'Operation failed without specific message';\r\n throw new Error(errorMessage);\r\n }\r\n\r\n if (responseBody.data.operation_status === 'SUCCESS') {\r\n return responseBody.data;\r\n }\r\n\r\n throw new Error(`Unknown operation status: ${responseBody.data.operation_status}`);\r\n}\r\n\r\nconst userConfirmEmailDoboard = async (emailConfirmationToken) => {\r\n const data = {\r\n email_confirmation_token: encodeURIComponent(emailConfirmationToken)\r\n }\r\n const result = await spotfixApiCall(data, 'user_confirm_email');\r\n return {\r\n sessionId: result.session_id,\r\n userId: result.user_id,\r\n email: result.email,\r\n accounts: result.accounts,\r\n operationStatus: result.operation_status\r\n };\r\n};\r\n\r\nconst createTaskDoboard = async (sessionId, taskDetails) => {\r\n const accountId = taskDetails.accountId;\r\n const data = {\r\n session_id: sessionId,\r\n project_token: taskDetails.projectToken,\r\n project_id: taskDetails.projectId,\r\n user_id: localStorage.getItem('spotfix_user_id'),\r\n name: taskDetails.taskTitle,\r\n comment: taskDetails.taskDescription,\r\n meta: taskDetails.taskMeta,\r\n task_type: 'PUBLIC'\r\n }\r\n const result = await spotfixApiCall(data, 'task_add', accountId);\r\n return {\r\n taskId: result.task_id,\r\n }\r\n};\r\n\r\nconst createTaskCommentDoboard = async (accountId, sessionId, taskId, comment, projectToken, status = 'ACTIVE') => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n task_id: taskId,\r\n comment: comment,\r\n status: status\r\n }\r\n const result = await spotfixApiCall(data, 'comment_add', accountId);\r\n return {\r\n commentId: result.comment_id,\r\n };\r\n};\r\n\r\nconst attachmentAddDoboard = async (fileData) => {\r\n const accountId = fileData.params.accountId;\r\n const data = {\r\n session_id: fileData.sessionId,\r\n project_token: fileData.params.projectToken,\r\n account_id: fileData.params.accountId,\r\n comment_id: fileData.commentId,\r\n filename: fileData.fileName,\r\n file: fileData.fileBinary,\r\n attachment_order: fileData.attachmentOrder\r\n }\r\n const result = await spotfixApiCall(data, 'attachment_add', accountId);\r\n // @ToDo need to handle result?\r\n};\r\n\r\nconst registerUserDoboard = async (projectToken, accountId, email, nickname, pageURL) => {\r\n let data = {\r\n project_token: projectToken,\r\n account_id: accountId,\r\n confirmation_url: email,\r\n }\r\n if (email && nickname) {\r\n data.email = email;\r\n data.name = nickname;\r\n }\r\n\r\n if (localStorage.getItem('bot_detector_event_token')) {\r\n try {\r\n const botDetectorData = JSON.parse(localStorage.getItem('bot_detector_event_token'));\r\n if (botDetectorData?.value) {\r\n data.bot_detector_event_token = botDetectorData?.value;\r\n }\r\n } catch (error) {\r\n data.bot_detector_event_token = '';\r\n }\r\n }\r\n const result = await spotfixApiCall(data, 'user_registration');\r\n return {\r\n sessionId: result.session_id,\r\n userId: result.user_id,\r\n email: result.email,\r\n accountExists: result.user_email_confirmed === 1,\r\n operationMessage: result.operation_message,\r\n operationStatus: result.operation_status,\r\n userEmailConfirmed: result.user_email_confirmed,\r\n };\r\n};\r\n\r\nconst loginUserDoboard = async (email, password) => {\r\n const data = {\r\n email: email,\r\n password: password,\r\n }\r\n const result = await spotfixApiCall(data, 'user_authorize');\r\n return {\r\n sessionId: result.session_id,\r\n userId: result.user_id,\r\n email: result.email,\r\n accountExists: result.user_email_confirmed === 1,\r\n operationMessage: result.operation_message,\r\n operationStatus: result.operation_status,\r\n userEmailConfirmed: result.user_email_confirmed,\r\n }\r\n}\r\n\r\nconst logoutUserDoboard = async (projectToken, accountId) => {\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n if(sessionId && accountId) {\r\n const data = {\r\n session_id: sessionId,\r\n };\r\n\r\n const email = localStorage.getItem('spotfix_email') || '';\r\n\r\n if (email && email.includes('spotfix_')) {\r\n data.project_token = projectToken;\r\n }\r\n\r\n const result = await spotfixApiCall(data, 'user_unauthorize', accountId);\r\n if (result.operation_status === 'SUCCESS') {\r\n clearLocalstorageOnLogout();\r\n }\r\n }\r\n}\r\n\r\nconst getTasksDoboard = async (projectToken, sessionId, accountId, projectId, userId) => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n project_id: projectId,\r\n task_type: 'PUBLIC'\r\n }\r\n if ( userId ) {\r\n data.user_id = userId;\r\n }\r\n const result = await spotfixApiCall(data, 'task_get', accountId);\r\n const tasks = result.tasks.map(task => ({\r\n taskId: task.task_id,\r\n taskTitle: task.name,\r\n taskLastUpdate: task.updated,\r\n taskCreated: task.created,\r\n taskCreatorTaskUser: task.creator_user_id,\r\n taskMeta: task.meta,\r\n taskStatus: task.status,\r\n }));\r\n\r\n storageSaveTasksCount(tasks);\r\n\r\n return tasks;\r\n}\r\n\r\n\r\nconst getTasksCommentsDoboard = async (sessionId, accountId, projectToken, status = 'ACTIVE') => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n status: status\r\n }\r\n const result = await spotfixApiCall(data, 'comment_get', accountId);\r\n return result.comments.map(comment => ({\r\n taskId: comment.task_id,\r\n commentId: comment.comment_id,\r\n userId: comment.user_id,\r\n commentBody: comment.comment,\r\n commentDate: comment.updated,\r\n status: comment.status,\r\n issueTitle: comment.task_name,\r\n }));\r\n};\r\n\r\nconst getUserDoboard = async (sessionId, projectToken, accountId, userId) => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n }\r\n if (userId) data.user_id = userId;\r\n\r\n const result = await spotfixApiCall(data, 'user_get', accountId);\r\n return result.users;\r\n\r\n // @ToDo Need to handle these two different answers?\r\n /*// Format 1: users inside data\r\n if (responseBody.data && responseBody.data.operation_status) {\r\n if (responseBody.data.operation_status === 'FAILED') {\r\n throw new Error(responseBody.data.operation_message);\r\n }\r\n if (responseBody.data.operation_status === 'SUCCESS') {\r\n if (Array.isArray(responseBody.data.users)) {\r\n return responseBody.data.users;\r\n }\r\n return [];\r\n }\r\n }\r\n // Format 2: users at the top level\r\n if (responseBody.operation_status) {\r\n if (responseBody.operation_status === 'FAILED') {\r\n throw new Error(responseBody.operation_message);\r\n }\r\n if (responseBody.operation_status === 'SUCCESS') {\r\n if (Array.isArray(responseBody.users)) {\r\n return responseBody.users;\r\n }\r\n return [];\r\n }\r\n }*/\r\n};\r\n\r\nconst userUpdateDoboard = async (projectToken, accountId, sessionId, userId, timezone) => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n user_id: userId,\r\n timestamp: timezone\r\n }\r\n await spotfixApiCall(data, 'user_update', accountId);\r\n return {\r\n success: true\r\n };\r\n}\r\n\r\nconst getReleaseVersion = async () => {\r\n try {\r\n const res = await fetch('https://api.github.com/repos/CleanTalk/SpotFix/releases');\r\n const data = await res.json();\r\n\r\n if (data.length > 0 && data[0].tag_name) {\r\n storageSaveSpotfixVersion(data[0].tag_name);\r\n return data[0].tag_name;\r\n }\r\n\r\n return null;\r\n } catch (err) {\r\n return null;\r\n }\r\n};\r\n\r\n\nconst SPOTFIX_VERSION = \"1.1.5\";\r\n\nasync function confirmUserEmail(emailConfirmationToken, params) {\r\n\tconst result = await userConfirmEmailDoboard(emailConfirmationToken);\r\n\t// Save session data to LS\r\n\tlocalStorage.setItem('spotfix_email', result.email);\r\n\tlocalStorage.setItem('spotfix_session_id', result.sessionId);\r\n\tlocalStorage.setItem('spotfix_user_id', result.userId);\r\n\r\n\t// Get pending task from LS\r\n\tconst pendingTaskRaw = localStorage.getItem('spotfix_pending_task');\r\n\tif (!pendingTaskRaw) throw new Error('No pending task data');\r\n\r\n\tlet pendingTask;\r\n\ttry {\r\n\t\tpendingTask = JSON.parse(pendingTaskRaw);\r\n\t} catch (error) {\r\n\t\tthrow new Error('Invalid pending task data');\r\n\t}\r\n\r\n\t// Form taskDetails for task creation\r\n\tconst taskDetails = {\r\n\t\ttaskTitle: pendingTask.selectedText || 'New Task',\r\n\t\ttaskDescription: pendingTask.description || '',\r\n\t\tselectedData: pendingTask,\r\n\t\tprojectToken: params.projectToken,\r\n\t\tprojectId: params.projectId,\r\n\t\taccountId: params.accountId,\r\n\t\ttaskMeta: JSON.stringify(pendingTask)\r\n\t};\r\n\r\n\t// Create task\r\n\tconst createdTask = await handleCreateTask(result.sessionId, taskDetails);\r\n\t// Clear pending task\r\n\tlocalStorage.removeItem('spotfix_pending_task');\r\n\r\n\t// Return created task\r\n\treturn createdTask;\r\n}\r\n\r\nasync function getTasksFullDetails(params, tasks, currentActiveTaskId) {\r\n if (tasks.length > 0) {\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n const comments = await getTasksCommentsDoboard(sessionId, params.accountId, params.projectToken);\r\n const users = await getUserDoboard(sessionId, params.projectToken, params.accountId);\r\n\t\tconst foundTask = tasks.find(item => +item.taskId === +currentActiveTaskId);\r\n\r\n return {\r\n comments: comments,\r\n users: users,\r\n\t\t\ttaskStatus: foundTask?.taskStatus,\r\n };\r\n }\r\n}\r\n\r\nasync function getUserDetails(params) {\r\n\t\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\t\tconst currentUserId = localStorage.getItem('spotfix_user_id');\r\n\t\tif(currentUserId) {\r\n\t\t\tconst users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId);\r\n\t\t\treturn users[0] || {};\r\n\t\t}\r\n}\r\n\r\nasync function handleCreateTask(sessionId, taskDetails) {\r\n\ttry {\r\n\t\tconst result = await createTaskDoboard(sessionId, taskDetails);\r\n\t\tif (result && result.taskId && taskDetails.taskDescription) {\r\n const sign = `


The spot has been posted at the following URL ${window.location.href}`;\r\n\t\t\tawait addTaskComment({\r\n\t\t\t\tprojectToken: taskDetails.projectToken,\r\n\t\t\t\taccountId: taskDetails.accountId\r\n\t\t\t}, result.taskId, taskDetails.taskDescription+sign);\r\n\t\t}\r\n\t\treturn result;\r\n\t} catch (err) {\r\n\t\tthrow err;\r\n\t}\r\n}\r\n\r\nasync function addTaskComment(params, taskId, commentText) {\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tif (!sessionId) throw new Error('No session');\r\n\tif (!params.projectToken || !params.accountId) throw new Error('Missing params');\r\n\treturn await createTaskCommentDoboard(params.accountId, sessionId, taskId, commentText, params.projectToken);\r\n}\r\n\r\nfunction getUserTasks(params) {\r\n\tif (!localStorage.getItem('spotfix_session_id')) {\r\n\t\treturn {};\r\n\t}\r\n\tconst projectToken = params.projectToken;\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tconst userId = localStorage.getItem('spotfix_user_id');\r\n\treturn getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId, userId);\r\n}\r\n\r\nasync function getAllTasks(params) {\r\n\tif (!localStorage.getItem('spotfix_session_id')) {\r\n\t\treturn {};\r\n\t}\r\n\tconst projectToken = params.projectToken;\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tconst tasksData = await getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId);\r\n\r\n // Get only tasks with metadata\r\n\tconst filteredTaskData = tasksData.filter(task => {\r\n return task.taskMeta;\r\n });\r\n\r\n return filteredTaskData;\r\n}\r\n\r\nfunction formatDate(dateStr) {\r\n\t const months = [\r\n\t \t\"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\r\n\t \t\"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\r\n\t ];\r\n\t // dateStr expected format: 'YYYY-MM-DD HH:mm:ss' or 'YYYY-MM-DDTHH:mm:ssZ'\r\n\t if (!dateStr) return { date: '', time: '' };\r\n\t let dateObj;\r\n\t if (dateStr.includes('T')) {\r\n\t dateObj = new Date(dateStr);\r\n\t } else if (dateStr.includes(' ')) {\r\n\t dateObj = new Date(dateStr.replace(' ', 'T'));\r\n\t } else {\r\n\t dateObj = new Date(dateStr);\r\n\t }\r\n\t if (isNaN(dateObj.getTime())) return { date: '', time: '' };\r\n\r\n\t // Adjust to local timezone\r\n\t const offsetMinutes = dateObj.getTimezoneOffset();\r\n\t let localDateObj = new Date(dateObj.getTime() - offsetMinutes * 60000);\r\n\r\n\t const month = months[localDateObj.getMonth()];\r\n\t const day = localDateObj.getDate();\r\n\t const date = `${month} ${day}`;\r\n\t const hours = localDateObj.getHours().toString().padStart(2, '0');\r\n\t const minutes = localDateObj.getMinutes().toString().padStart(2, '0');\r\n\t const time = `${hours}:${minutes}`;\r\n\t return { date, time };\r\n}\r\n\r\nfunction getTaskAuthorDetails(params, taskId) {\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tconst mockUsersData =\r\n\t\t[\r\n\t\t\t{\r\n\t\t\t\t'taskId': '1',\r\n\t\t\t\t'taskAuthorAvatarImgSrc': 'https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg',\r\n\t\t\t\t'taskAuthorName': 'Test All Issues Single Author Name'\r\n\t\t\t}\r\n\t\t]\r\n\r\n\tconst defaultData =\r\n\t\t{\r\n\t\t\t'taskId': null,\r\n\t\t\t'taskAuthorAvatarImgSrc': null,\r\n\t\t\t'taskAuthorName': 'Task Author'\r\n\t\t};\r\n\r\n\tconst data = mockUsersData.find((element) => element.taskId === taskId);\r\n\treturn data === undefined ? defaultData : data;\r\n}\r\n\r\nfunction getIssuesCounterString(onPageSpotsCount, totalSpotsCount) {\r\n\treturn ` (${onPageSpotsCount}/${totalSpotsCount})`;\r\n}\r\n\r\n// Get the author's avatar\r\nfunction getAvatarSrc(author) {\r\n\tif (author && author.avatar) {\r\n\t\tif (typeof author.avatar === 'object' && author.avatar.m) {\r\n\t\t\treturn author.avatar.m;\r\n\t\t} else if (typeof author.avatar === 'string') {\r\n\t\t\treturn author.avatar;\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n}\r\n\r\n// Get the author's name\r\nfunction getAuthorName(author) {\r\n\tif (author) {\r\n\t\tif (author.name && author.name.trim().length > 0) {\r\n\t\t\treturn author.name;\r\n\t\t} else if (author.email && author.email.trim().length > 0) {\r\n\t\t\treturn author.email;\r\n\t\t}\r\n\t}\r\n\treturn 'Unknown Author';\r\n}\r\n\r\nfunction registerUser(taskDetails) {\r\n\tconst userEmail = taskDetails.userEmail;\r\n\tconst userName = taskDetails.userName;\r\n\tconst projectToken = taskDetails.projectToken;\r\n\tconst accountId = taskDetails.accountId;\r\n\tconst pageURL = taskDetails.selectedData.pageURL ? taskDetails.selectedData.pageURL : window.location.href;\r\n\r\n\tconst resultRegisterUser = (showMessageCallback) => registerUserDoboard(projectToken, accountId, userEmail, userName, pageURL)\r\n\t\t.then(response => {\r\n\t\t\tif (response.accountExists) {\r\n\t\t\t\tdocument.querySelector(\".doboard_task_widget-accordion>.doboard_task_widget-input-container\").innerText = ksesFilter('Account already exists. Please, login usin your password.');\r\n\t\t\t\tdocument.querySelector(\".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden\").classList.remove('hidden');\r\n\t\t\t\tdocument.getElementById(\"doboard_task_widget-user_password\").focus();\r\n\t\t\t} else if (response.sessionId) {\r\n\t\t\t\tlocalStorage.setItem('spotfix_session_id', response.sessionId);\r\n\t\t\t\tlocalStorage.setItem('spotfix_user_id', response.userId);\r\n\t\t\t\tlocalStorage.setItem('spotfix_email', response.email);\r\n\t\t\t\tuserUpdate(projectToken, accountId);\r\n\t\t\t} else if (response.operationStatus === 'SUCCESS' && response.operationMessage && response.operationMessage.length > 0) {\r\n\t\t\t\tif (response.operationMessage == 'Waiting for email confirmation') {\r\n\t\t\t\t\tresponse.operationMessage = 'Waiting for an email confirmation. Please check your Inbox.';\r\n\t\t\t\t}\r\n\t\t\t\tif (typeof showMessageCallback === 'function') {\r\n\t\t\t\t\tshowMessageCallback(response.operationMessage, 'notice');\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tthrow new Error('Session ID not found in response');\r\n\t\t\t}\r\n\t\t})\r\n\t\t.catch(error => {\r\n\t\t\tthrow error;\r\n\t\t});\r\n\r\n\t\treturn resultRegisterUser;\r\n}\r\n\r\nfunction loginUser(taskDetails) {\r\n\tconst userEmail = taskDetails.userEmail;\r\n\tconst userPassword = taskDetails.userPassword;\r\n\r\n\treturn (showMessageCallback) => loginUserDoboard(userEmail, userPassword)\r\n\t\t.then(response => {\r\n\t\t\tif (response.sessionId) {\r\n\t\t\t\tlocalStorage.setItem('spotfix_session_id', response.sessionId);\r\n\t\t\t\tlocalStorage.setItem('spotfix_user_id', response.userId);\r\n\t\t\t\tlocalStorage.setItem('spotfix_email', userEmail);\r\n\t\t\t} else if (response.operationStatus === 'SUCCESS' && response.operationMessage && response.operationMessage.length > 0) {\r\n\t\t\t\tif (typeof showMessageCallback === 'function') {\r\n\t\t\t\t\tshowMessageCallback(response.operationMessage, 'notice');\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tthrow new Error('Session ID not found in response');\r\n\t\t\t}\r\n\t\t})\r\n\t\t.catch(error => {\r\n\t\t\tthrow error;\r\n\t\t});\r\n}\r\n\r\nfunction userUpdate(projectToken, accountId) {\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tconst userId = localStorage.getItem('spotfix_user_id');\r\n\tconst timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\r\n\r\n\treturn userUpdateDoboard(projectToken, accountId, sessionId, userId, timezone);\r\n}\r\n\r\nfunction spotFixSplitUrl(url) {\r\n\ttry {\r\n\t\tif (!url || url.trim() === '') {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst u = new URL(url);\r\n\t\tconst domain = u.host;\r\n\r\n\t\tconst segments = u.pathname.split('/').filter(Boolean);\r\n\r\n\t\tif (segments.length === 0) {\r\n\t\t\treturn domain;\r\n\t\t}\r\n\r\n\t\tconst reversed = segments.reverse();\r\n\t\treversed.push(domain);\r\n\t\treturn reversed.join(' / ');\r\n\t} catch (error) {\r\n\t\treturn '';\r\n\t}\r\n\r\n}\r\n\r\nfunction setToggleStatus(rootElement){\r\n\tconst clickHandler = () => {\r\n\t\tconst timer = setTimeout(() => {\r\n\t\t\tlocalStorage.setItem('spotfix_widget_is_closed', '1');\r\n\t\t\trootElement.hide();\r\n\t\t\tclearTimeout(timer);\r\n\t\t}, 300);\r\n\t};\r\n\tconst toggle = document.getElementById('widget_visibility');\r\n\tif(toggle) {\r\n\t\ttoggle.checked = true;\r\n\t\ttoggle.addEventListener('click', clickHandler);\r\n\t}\r\n}\r\n\r\nfunction checkLogInOutButtonsVisible (){\r\n\tif(!localStorage.getItem('spotfix_session_id')) {\r\n\t\tconst el = document\r\n\t\t\t.getElementById('doboard_task_widget-user_menu-logout_button')\r\n\t\t\t?.closest('.doboard_task_widget-user_menu-item');\r\n\t\t\tif(el) el.style.display = 'none';\r\n\t} else {\r\n\t\tconst el = document.getElementById('doboard_task_widget-user_menu-signlog_button');\r\n\t\tif(el) el.style.display = 'none';\r\n\t}\r\n}\r\n\r\nfunction changeSize(container){\r\n\tif(container && +localStorage.getItem('maximize')){\r\n\t\tcontainer.classList.add('doboard_task_widget-container-maximize');\r\n\t} else if(container) {\r\n\t\tcontainer.classList.remove('doboard_task_widget-container-maximize');\r\n\t}\r\n}\r\n\n/**\r\n * Widget class to create a task widget\r\n */\r\nclass CleanTalkWidgetDoboard {\r\n selectedText = '';\r\n selectedData = {};\r\n widgetElement = null;\r\n params = {};\r\n currentActiveTaskId = 0;\r\n savedIssuesQuantityOnPage = 0;\r\n savedIssuesQuantityAll = 0;\r\n allTasksData = {};\r\n srcVariables = {};\r\n\r\n /**\r\n * Constructor\r\n */\r\n constructor(selectedData, type) {\r\n this.selectedData = selectedData || '';\r\n this.selectedText = selectedData?.selectedText || '';\r\n this.init(type);\r\n this.srcVariables = {\r\n buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'),\r\n iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'),\r\n iconPlus: SpotFixSVGLoader.getAsDataURI('iconPlus'),\r\n iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'),\r\n chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardGreen: SpotFixSVGLoader.getAsDataURI('logoDoBoardGreen'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\r\n iconMarker: SpotFixSVGLoader.getAsDataURI('iconMarker'),\r\n iconSpotPublic: SpotFixSVGLoader.getAsDataURI('iconSpotPublic'),\r\n iconSpotPrivate: SpotFixSVGLoader.getAsDataURI('iconSpotPrivate'),\r\n iconLinkChain: SpotFixSVGLoader.getAsDataURI('iconLinkChain'),\r\n };\r\n this.fileUploader = new FileUploader(this.escapeHtml);\r\n }\r\n\r\n /**\r\n * Initialize the widget\r\n */\r\n async init(type) {\r\n this.params = this.getParams();\r\n\r\n // Check if email_confirmation_token is in URL\r\n const urlParams = new URLSearchParams(window.location.search);\r\n const emailToken = urlParams.get('email_confirmation_token');\r\n if (emailToken) {\r\n try {\r\n // Confirm email and create task\r\n const createdTask = await confirmUserEmail(emailToken, this.params);\r\n this.allTasksData = await getAllTasks(this.params);\r\n // Open task interface\r\n this.currentActiveTaskId = createdTask.taskId;\r\n type = 'concrete_issue';\r\n storageSetWidgetIsClosed(false);\r\n // Clear email_confirmation_token from URL\r\n urlParams.delete('email_confirmation_token');\r\n const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '');\r\n window.history.replaceState({}, document.title, newUrl);\r\n } catch (err) {\r\n this.registrationShowMessage('Error confirming email: ' + err.message, 'error');\r\n }\r\n } else {\r\n // Load all tasks\r\n const isWidgetClosed = localStorage.getItem('spotfix_widget_is_closed');\r\n if((isWidgetClosed && !this.selectedText) || !isWidgetClosed){\r\n this.allTasksData = await getAllTasks(this.params);\r\n }\r\n }\r\n\r\n // Check if any task has updates\r\n let taskHasSiteOwnerUpdate;\r\n\r\n if (storageTasksHasUnreadUpdates()) {\r\n taskHasSiteOwnerUpdate = true;\r\n } else {\r\n if (type === 'wrap_review') {\r\n taskHasSiteOwnerUpdate = await checkIfTasksHasSiteOwnerUpdates(\r\n this.allTasksData,\r\n this.params\r\n );\r\n }\r\n }\r\n storageSaveTasksUpdateData(this.allTasksData);\r\n //check to hide on first run\r\n if (!storageWidgetCloseIsSet()) {\r\n storageSetWidgetIsClosed(true);\r\n }\r\n //check to show if any task has site owner updates\r\n if (taskHasSiteOwnerUpdate) {\r\n\r\n storageSetWidgetIsClosed(false);\r\n }\r\n this.widgetElement = await this.createWidgetElement(type);\r\n this.bindWidgetInputsInteractive();\r\n }\r\n\r\n getParams() {\r\n const script = document.querySelector(`script[src*=\"doboard-widget-bundle.\"]`);\r\n if ( ! script || ! script.src ) {\r\n throw new Error('Script not provided');\r\n }\r\n\r\n const url = new URL(script.src);\r\n let params = Object.fromEntries(url.searchParams.entries());\r\n if ( ! params ) {\r\n throw new Error('Script params not provided');\r\n }\r\n if ( ! params.projectToken || ! params.accountId || ! params.projectId ) {\r\n throw new Error('Necessary script params not provided');\r\n\r\n }\r\n return params;\r\n }\r\n\r\n /**\r\n * Binding events to create a task\r\n */\r\n bindCreateTaskEvents() {\r\n const submitButton = document.getElementById('doboard_task_widget-submit_button');\r\n\r\n if (submitButton) {\r\n submitButton.addEventListener('click', async () => {\r\n // Check required fields: Report about and Description\r\n const taskTitleElement = document.getElementById('doboard_task_widget-title');\r\n const taskTitle = taskTitleElement.value;\r\n if ( ! taskTitle ) {\r\n taskTitleElement.style.borderColor = 'red';\r\n taskTitleElement.focus();\r\n taskTitleElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n const taskDescriptionElement = document.getElementById('doboard_task_widget-description')\r\n const taskDescription = taskDescriptionElement.value;\r\n if ( ! taskDescription ) {\r\n taskDescriptionElement.style.borderColor = 'red';\r\n taskDescriptionElement.focus();\r\n taskDescriptionElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n\r\n // If login section is open, check required fields: Nickname, Email\r\n let userName = '';\r\n let userEmail = '';\r\n let userPassword = '';\r\n const loginSectionElement = document.querySelector('.doboard_task_widget-login');\r\n\r\n if ( loginSectionElement && loginSectionElement.classList.contains('active') ) {\r\n const userEmailElement = document.getElementById('doboard_task_widget-user_email');\r\n const userNameElement = document.getElementById('doboard_task_widget-user_name');\r\n const userPasswordElement = document.getElementById('doboard_task_widget-user_password');\r\n\r\n userEmail = userEmailElement.value;\r\n if ( ! userEmail ) {\r\n userEmailElement.style.borderColor = 'red';\r\n userEmailElement.focus();\r\n userEmailElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n\r\n // This is the registration request\r\n if ( userEmailElement && userNameElement ) {\r\n userName = userNameElement.value;\r\n if ( ! userName ) {\r\n userNameElement.style.borderColor = 'red';\r\n userNameElement.focus();\r\n userNameElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n }\r\n\r\n // This is the login request\r\n if ( userEmailElement && userPasswordElement && ! userNameElement ) {\r\n userPassword = userPasswordElement.value;\r\n if ( ! userPassword ) {\r\n userPasswordElement.style.borderColor = 'red';\r\n userPasswordElement.focus();\r\n userPasswordElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n }\r\n\r\n }\r\n\r\n // If it is the login request\r\n const userEmailElement = document.getElementById('doboard_task_widget-user_email');\r\n userEmail = userEmailElement.value;\r\n\r\n // Make the submit button disable with spinner\r\n const submitButton = document.getElementById('doboard_task_widget-submit_button');\r\n submitButton.disabled = true;\r\n submitButton.innerText = ksesFilter('Creating spot...');\r\n\r\n let taskDetails = {\r\n taskTitle: taskTitle,\r\n taskDescription: taskDescription,\r\n //typeSend: typeSend,\r\n selectedData: this.selectedData,\r\n projectToken: this.params.projectToken,\r\n projectId: this.params.projectId,\r\n accountId: this.params.accountId,\r\n taskMeta: JSON.stringify(this.selectedData ? this.selectedData : { pageURL: window.location.href }),\r\n };\r\n\r\n if ( userEmail ) {\r\n taskDetails.userEmail = userEmail\r\n }\r\n if ( userName ) {\r\n taskDetails.userName = userName\r\n }\r\n if ( userPassword ) {\r\n taskDetails.userPassword = userPassword\r\n }\r\n\r\n // Save pending task in LS\r\n localStorage.setItem('spotfix_pending_task', JSON.stringify({\r\n ...this.selectedData,\r\n description: taskDescription\r\n }));\r\n\r\n let submitTaskResult;\r\n try {\r\n submitTaskResult = await this.submitTask(taskDetails);\r\n } catch (error) {\r\n this.registrationShowMessage(error.message);\r\n return;\r\n }\r\n\r\n // Return the submit button normal state\r\n submitButton.disabled = false;\r\n submitButton.style.cursor = 'pointer';\r\n\r\n if ( submitTaskResult.needToLogin ) {\r\n // @ToDo Do not know what to de here: throw an error or pass log message?\r\n return;\r\n }\r\n\r\n if ( submitTaskResult.isPublic !== undefined ) {\r\n this.selectedData.isPublic = submitTaskResult.isPublic\r\n }\r\n\r\n // refersh tasks list after creation\r\n this.allTasksData = await getAllTasks(this.params);\r\n // save updates\r\n storageSaveTasksUpdateData(this.allTasksData);\r\n\r\n this.selectedData = {};\r\n await this.createWidgetElement('all_issues');\r\n storageSetWidgetIsClosed(false);\r\n hideContainersSpinner(false);\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Create widget element\r\n * @return {HTMLElement} widget element\r\n */\r\n async createWidgetElement(type, showOnlyCurrentPage = false) {\r\n const widgetContainer = document.querySelector('.doboard_task_widget') ? document.querySelector('.doboard_task_widget') : document.createElement('div');\r\n widgetContainer.className = 'doboard_task_widget';\r\n widgetContainer.innerHTML = ksesFilter('');\r\n widgetContainer.removeAttribute('style');\r\n\r\n let templateName = '';\r\n let tasksFullDetails;\r\n\r\n let templateVariables = {};\r\n\r\n const config = window.SpotfixWidgetConfig;\r\n\r\n switch (type) {\r\n case 'create_issue':\r\n templateName = 'create_issue';\r\n this.type_name = templateName;\r\n templateVariables = {\r\n selectedText: this.selectedText,\r\n currentDomain: document.location.hostname || '',\r\n buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'),\r\n iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'),\r\n iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'),\r\n ...this.srcVariables\r\n };\r\n storageGetUserIsDefined() && storageSetWidgetIsClosed(false);\r\n break;\r\n case 'wrap':\r\n if (storageGetWidgetIsClosed()) {\r\n return;\r\n }\r\n\r\n templateName = 'wrap';\r\n templateVariables = {position: !Number.isNaN(Number(config?.verticalPosition))\r\n ? `${Number(config?.verticalPosition)}vh` : '0vh', ...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {position: !Number.isNaN(Number(config?.verticalPosition))\r\n ? `${Number(config?.verticalPosition)}vh` : '0vh', ...this.srcVariables};\r\n break;\r\n case 'all_issues':\r\n templateName = 'all_issues';\r\n this.type_name = templateName;\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'user_menu':\r\n templateName = 'user_menu';\r\n const version = localStorage.getItem('spotfix_app_version') || SPOTFIX_VERSION;\r\n templateVariables = {\r\n spotfixVersion: version ? 'Spotfix version ' + version + '.' : '',\r\n avatar: SpotFixSVGLoader.getAsDataURI('iconAvatar'),\r\n iconEye: SpotFixSVGLoader.getAsDataURI('iconEye'),\r\n iconDoor: SpotFixSVGLoader.getAsDataURI('iconDoor'),\r\n chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'),\r\n buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'),\r\n userName: 'Guest',\r\n email: localStorage.getItem('spotfix_email') || '',\r\n ...this.srcVariables};\r\n break;\r\n case 'concrete_issue':\r\n templateName = 'concrete_issue';\r\n this.type_name = templateName;\r\n // Update the number of tasks\r\n this.savedIssuesQuantityAll = Array.isArray(this.allTasksData) ? this.allTasksData.length : 0;\r\n // Calculate the number of issues on the current page\r\n this.savedIssuesQuantityOnPage = Array.isArray(this.allTasksData)\r\n ? this.allTasksData.filter(task => {\r\n try {\r\n const meta = task.taskMeta ? JSON.parse(task.taskMeta) : {};\r\n return meta.pageURL === window.location.href;\r\n } catch (e) { return false; }\r\n }).length\r\n : 0;\r\n\r\n templateVariables = {\r\n issueTitle: '...',\r\n issueComments: [],\r\n issuesCounter: getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll),\r\n ...this.srcVariables,\r\n };\r\n break;\r\n default:\r\n break;\r\n }\r\n widgetContainer.innerHTML = this.loadTemplate(templateName, templateVariables);\r\n document.body.appendChild(widgetContainer);\r\n\r\n // remove highlights before any screen called\r\n spotFixRemoveHighlights();\r\n const container = document.querySelector('.doboard_task_widget-container');\r\n switch (type) {\r\n case 'create_issue':\r\n\r\n if(container && +localStorage.getItem('maximize')){\r\n container.classList.add('doboard_task_widget-container-maximize');\r\n } else if(container) {\r\n container.classList.remove('doboard_task_widget-container-maximize');\r\n }\r\n // highlight selected item during task creation\r\n const selection = window.getSelection();\r\n const sessionIdExists = !!localStorage.getItem('spotfix_session_id');\r\n const email = localStorage.getItem('spotfix_email');\r\n\r\n if (sessionIdExists && email && !email.includes('spotfix_')) {\r\n document.querySelector('.doboard_task_widget-login').classList.add('hidden');\r\n }\r\n if (\r\n selection.type === 'Range'\r\n ) {\r\n const selectedData = spotFixGetSelectedData(selection);\r\n spotFixScrollToNodePath(selectedData.nodePath);\r\n this.positionWidgetContainer();\r\n }\r\n // bind creation events\r\n this.bindCreateTaskEvents();\r\n break;\r\n case 'wrap':\r\n await this.getTaskCount();\r\n document.querySelector('.doboard_task_widget-wrap').addEventListener('click', (e) => {\r\n const widgetElementClasses = e.currentTarget.classList;\r\n if (widgetElementClasses && !widgetElementClasses.contains('hidden')) {\r\n this.createWidgetElement('all_issues');\r\n }\r\n });\r\n hideContainersSpinner(false);\r\n break;\r\n case 'wrap_review':\r\n document.querySelector('#doboard_task_widget_button').addEventListener('click', (e) => {\r\n spotFixOpenWidget(this.selectedData, 'create_issue');\r\n });\r\n break;\r\n case 'all_issues':\r\n changeSize(container);\r\n\r\n spotFixRemoveHighlights();\r\n let issuesQuantityOnPage = 0;\r\n if (!this.allTasksData?.length) {\r\n this.allTasksData = await getAllTasks(this.params);\r\n }\r\n const tasks = this.allTasksData;\r\n tasksFullDetails = await getTasksFullDetails(this.params, tasks, this.currentActiveTaskId);\r\n let spotsToBeHighlighted = [];\r\n if (tasks.length > 0) {\r\n const currentURL = window.location.href;\r\n const sortedTasks = tasks.sort((a, b) => {\r\n const aIsHere = JSON.parse(a.taskMeta).pageURL === currentURL ? 1 : 0;\r\n const bIsHere = JSON.parse(b.taskMeta).pageURL === currentURL ? 1 : 0;\r\n return bIsHere - aIsHere;\r\n });\r\n\r\n document.querySelector(\".doboard_task_widget-all_issues-container\").innerHTML = '';\r\n\r\n for (let i = 0; i < sortedTasks.length; i++) {\r\n const elTask = sortedTasks[i];\r\n\r\n // Data from api\r\n const taskId = elTask.taskId;\r\n const taskTitle = elTask.taskTitle;\r\n const taskMetaString = elTask.taskMeta;\r\n let taskData = null;\r\n if (taskMetaString) {\r\n try {\r\n taskData = JSON.parse(taskMetaString);\r\n taskData.isFixed = elTask.taskStatus === 'DONE';\r\n taskData.taskId = elTask.taskId;\r\n } catch (error) {\r\n taskData = null;\r\n }\r\n }\r\n const currentPageURL = taskData ? taskData.pageURL : '';\r\n const taskNodePath = taskData ? taskData.nodePath : '';\r\n\r\n // Define publicity details\r\n let taskPublicStatusImgSrc = '';\r\n let taskPublicStatusHint = 'Task publicity is unknown'\r\n if (taskData && taskData.isPublic !== undefined) {\r\n if (taskData.isPublic) {\r\n taskPublicStatusImgSrc = this.srcVariables.iconSpotPublic;\r\n taskPublicStatusHint = 'The task is public';\r\n } else {\r\n taskPublicStatusImgSrc = this.srcVariables.iconSpotPrivate;\r\n taskPublicStatusHint = 'The task is private and visible only for registered DoBoard users';\r\n }\r\n }\r\n\r\n if(currentPageURL === window.location.href){\r\n issuesQuantityOnPage++;\r\n }\r\n\r\n if (!showOnlyCurrentPage || currentPageURL === window.location.href) {\r\n\r\n const taskFullDetails = getTaskFullDetails(tasksFullDetails, taskId)\r\n\r\n const avatarData = getAvatarData(taskFullDetails);\r\n const listIssuesTemplateVariables = {\r\n taskTitle: taskTitle || '',\r\n taskAuthorAvatarImgSrc: taskFullDetails.taskAuthorAvatarImgSrc,\r\n taskAuthorName: taskFullDetails.taskAuthorName,\r\n taskPublicStatusImgSrc: taskPublicStatusImgSrc,\r\n taskPublicStatusHint: taskPublicStatusHint,\r\n taskLastMessage: ksesFilter(taskFullDetails.lastMessageText),\r\n taskPageUrl: currentPageURL,\r\n iconLinkChain: this.srcVariables.iconLinkChain,\r\n taskFormattedPageUrl: spotFixSplitUrl(currentPageURL),\r\n taskLastUpdate: taskFullDetails.lastMessageTime,\r\n nodePath: this.sanitizeNodePath(taskNodePath),\r\n taskId: taskId,\r\n avatarCSSClass: avatarData.avatarCSSClass,\r\n avatarStyle: avatarData.avatarStyle,\r\n taskAuthorInitials: avatarData.taskAuthorInitials,\r\n initialsClass: avatarData.initialsClass,\r\n classUnread: '',\r\n elementBgCSSClass: elTask.taskStatus !== 'DONE' ? '' : 'doboard_task_widget-task_row-green',\r\n statusFixedHtml: elTask.taskStatus !== 'DONE' ? '' : this.loadTemplate('fixedHtml'),\r\n };\r\n\r\n const taskOwnerReplyIsUnread = storageProvidedTaskHasUnreadUpdates(taskFullDetails.taskId);\r\n if (taskOwnerReplyIsUnread) {\r\n listIssuesTemplateVariables.classUnread = 'unread';\r\n }\r\n document.querySelector(\".doboard_task_widget-all_issues-container\").innerHTML += this.loadTemplate('list_issues', listIssuesTemplateVariables);\r\n\r\n if ( this.isSpotHaveToBeHighlighted(taskData) ) {\r\n spotsToBeHighlighted.push(taskData);\r\n }\r\n }\r\n }\r\n this.savedIssuesQuantityOnPage = issuesQuantityOnPage;\r\n this.savedIssuesQuantityAll = tasks.length;\r\n spotFixHighlightElements(spotsToBeHighlighted, this);\r\n document.querySelector('.doboard_task_widget-header span').innerHTML += ksesFilter(' ' + getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll));\r\n }\r\n\r\n if (tasks.length === 0) {\r\n document.querySelector(\".doboard_task_widget-all_issues-container\").innerHTML = ksesFilter('
The issues list is empty
');\r\n }\r\n\r\n // Bind the click event to the task elements for scrolling to the selected text and Go to concrete issue interface by click issue-item row\r\n this.bindIssuesClick();\r\n hideContainersSpinner(false);\r\n break;\r\n case 'user_menu':\r\n\r\n setToggleStatus(this);\r\n checkLogInOutButtonsVisible();\r\n\r\n const user = await getUserDetails(this.params);\r\n const gitHubAppVersion = await getReleaseVersion();\r\n let spotfixVersion = '';\r\n const version = localStorage.getItem('spotfix_app_version') || gitHubAppVersion || SPOTFIX_VERSION;\r\n spotfixVersion = version ? `Spotfix version ${version}.` : '';\r\n\r\n templateVariables.spotfixVersion = spotfixVersion || '';\r\n\r\n if(user){\r\n templateVariables.userName = user.name || 'Guest';\r\n templateVariables.email = user.email || localStorage.getItem('spotfix_email') || '';\r\n if(user?.avatar?.s) templateVariables.avatar = user?.avatar?.s;\r\n }\r\n\r\n widgetContainer.innerHTML = this.loadTemplate('user_menu', templateVariables);\r\n document.body.appendChild(widgetContainer);\r\n setToggleStatus(this);\r\n checkLogInOutButtonsVisible();\r\n\r\n break;\r\n case 'concrete_issue':\r\n changeSize(container);\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n // Update issue title in the interface\r\n const issueTitleElement = document.querySelector('.doboard_task_widget-issue-title');\r\n if (issueTitleElement) {\r\n issueTitleElement.innerText = ksesFilter(taskDetails.issueTitle);\r\n }\r\n\r\n templateVariables.issueTitle = taskDetails?.issueTitle;\r\n templateVariables.issueComments = taskDetails?.issueComments;\r\n\r\n\r\n // Highlight the task's selected text\r\n let nodePath = null;\r\n const currentTaskData = this.allTasksData.find((element) => String(element.taskId) === String(taskDetails.taskId));\r\n let meta = null;\r\n\r\n if (currentTaskData && currentTaskData.taskMeta) {\r\n try {\r\n meta = JSON.parse(currentTaskData.taskMeta);\r\n nodePath = meta.nodePath || null;\r\n } catch (e) { nodePath = null; meta = null; }\r\n }\r\n\r\n templateVariables.taskPageUrl = meta.pageURL;\r\n const taskFormattedPageUrl = meta.pageURL.replace(window.location.origin, '');\r\n templateVariables.taskFormattedPageUrl = taskFormattedPageUrl.length < 2\r\n ? meta.pageURL.replace(window.location.protocol + '/', '') : taskFormattedPageUrl;\r\n templateVariables.contenerClasess = +localStorage.getItem('maximize')\r\n ? 'doboard_task_widget-container-maximize doboard_task_widget-container' : 'doboard_task_widget-container'\r\n widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\r\n\r\n // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\r\n\r\n if (meta && nodePath) {\r\n // Pass the task meta object as an array\r\n spotFixHighlightElements([meta], this);\r\n if (typeof spotFixScrollToNodePath === 'function') {\r\n spotFixScrollToNodePath(nodePath);\r\n }\r\n }\r\n\r\n const issuesCommentsContainer = document.querySelector('.doboard_task_widget-concrete_issues-container');\r\n let dayMessagesData = [];\r\n const initIssuerID = localStorage.getItem('spotfix_user_id');\r\n let userIsIssuer = false;\r\n if ( taskDetails.issueComments.length > 0 ) {\r\n storageRemoveUnreadUpdateForTaskID(taskDetails.taskId);\r\n issuesCommentsContainer.innerHTML = ksesFilter('');\r\n for (const comment of taskDetails.issueComments) {\r\n userIsIssuer = Number(initIssuerID) === Number(comment.commentUserId);\r\n const avatarData = getAvatarData({\r\n taskAuthorAvatarImgSrc: comment.commentAuthorAvatarSrc,\r\n taskAuthorName: comment.commentAuthorName,\r\n });\r\n const commentData = {\r\n commentAuthorName: comment.commentAuthorName,\r\n commentBody: comment.commentBody,\r\n commentDate: comment.commentDate,\r\n commentTime: comment.commentTime,\r\n issueTitle: templateVariables.issueTitle,\r\n avatarCSSClass: avatarData.avatarCSSClass,\r\n avatarStyle: avatarData.avatarStyle,\r\n taskAuthorInitials: avatarData.taskAuthorInitials,\r\n initialsClass: avatarData.initialsClass,\r\n issueMessageClassOwner: userIsIssuer ? 'owner' : 'guest',\r\n };\r\n if (dayMessagesData[comment.commentDate] === undefined) {\r\n dayMessagesData[comment.commentDate] = [];\r\n dayMessagesData[comment.commentDate].push(commentData);\r\n } else {\r\n dayMessagesData[comment.commentDate].push(commentData);\r\n }\r\n }\r\n let daysWrapperHTML = '';\r\n\r\n for (const day in dayMessagesData) {\r\n let currentDayMessages = dayMessagesData[day];\r\n let dayMessagesWrapperHTML = '';\r\n currentDayMessages.sort((a, b) => a.commentTime.localeCompare(b.commentTime));\r\n for (const messageId in currentDayMessages) {\r\n let currentMessageTemplateVariables = currentDayMessages[messageId];\r\n dayMessagesWrapperHTML += this.loadTemplate('concrete_issue_messages', currentMessageTemplateVariables);\r\n }\r\n daysWrapperHTML += this.loadTemplate('concrete_issue_day_content',\r\n {\r\n dayContentMonthDay: day,\r\n dayContentMessages: dayMessagesWrapperHTML,\r\n statusFixedHtml: tasksFullDetails?.taskStatus !== 'DONE' ? '' : this.loadTemplate('fixedTaskHtml')\r\n },\r\n );\r\n }\r\n issuesCommentsContainer.innerHTML = daysWrapperHTML;\r\n } else {\r\n issuesCommentsContainer.innerHTML = ksesFilter('No comments');\r\n }\r\n\r\n // textarea (new comment) behaviour\r\n const textarea = document.querySelector('.doboard_task_widget-send_message_input');\r\n if (textarea) {\r\n function handleTextareaChange() {\r\n const triggerChars = 40;\r\n\r\n if (this.value.length > triggerChars) {\r\n this.classList.add('high');\r\n } else {\r\n this.classList.remove('high');\r\n }\r\n }\r\n textarea.addEventListener('input', handleTextareaChange)\r\n textarea.addEventListener('change', handleTextareaChange)\r\n }\r\n\r\n // Hide spinner preloader\r\n hideContainersSpinner();\r\n\r\n // Scroll to the bottom comments\r\n setTimeout(() => {\r\n const contentContainer = document.querySelector('.doboard_task_widget-content');\r\n contentContainer.scrollTo({\r\n top: contentContainer.scrollHeight,\r\n behavior: 'smooth'\r\n });\r\n }, 0);\r\n\r\n const sendButton = document.querySelector('.doboard_task_widget-send_message_button');\r\n if (sendButton) {\r\n this.fileUploader.init();\r\n let widgetClass = this;\r\n sendButton.addEventListener('click', async (e) => {\r\n e.preventDefault();\r\n\r\n const sendMessageContainer = sendButton.closest('.doboard_task_widget-send_message');\r\n const input = sendMessageContainer.querySelector('.doboard_task_widget-send_message_input');\r\n\r\n const commentText = input.value.trim();\r\n if (!commentText) return;\r\n\r\n // Add other fields handling here\r\n\r\n input.disabled = true;\r\n sendButton.disabled = true;\r\n\r\n let newCommentResponse = null;\r\n\r\n try {\r\n newCommentResponse = await addTaskComment(this.params, this.currentActiveTaskId, commentText);\r\n input.value = '';\r\n await this.createWidgetElement('concrete_issue');\r\n hideContainersSpinner(false);\r\n } catch (err) {\r\n alert('Error when adding a comment: ' + err.message);\r\n }\r\n\r\n if (widgetClass.fileUploader.hasFiles() && newCommentResponse !== null && newCommentResponse.hasOwnProperty('commentId')) {\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n const attachmentsSendResult = await widgetClass.fileUploader.sendAttachmentsForComment(widgetClass.params, sessionId, newCommentResponse.commentId);\r\n if (!attachmentsSendResult.success) {\r\n widgetClass.fileUploader.showError('Some files where no sent, see details in the console.');\r\n const toConsole = JSON.stringify(attachmentsSendResult);\r\n console.log(toConsole);\r\n }\r\n }\r\n\r\n input.disabled = false;\r\n sendButton.disabled = false;\r\n });\r\n }\r\n\r\n break;\r\n\r\n default:\r\n break;\r\n }\r\n\r\n const backToAllIssuesController = document.querySelector('.doboard_task_widget_return_to_all');\r\n const widgetClass = this;\r\n if ( backToAllIssuesController ) {\r\n backToAllIssuesController.addEventListener('click', function(e, self = widgetClass) {\r\n self.createWidgetElement('all_issues');\r\n });\r\n }\r\n\r\n const paperclipController = document.querySelector('.doboard_task_widget-send_message_paperclip');\r\n if ( paperclipController ) {\r\n this.fileUploader.bindPaperClipAction(paperclipController);\r\n }\r\n\r\n document.querySelector('.doboard_task_widget-close_btn')?.addEventListener('click', (e) => {\r\n this.hide();\r\n }) || '';\r\n\r\n document.querySelector('#openUserMenuButton')?.addEventListener('click', () => {\r\n this.createWidgetElement('user_menu')\r\n }) || '';\r\n\r\n document.querySelector('#doboard_task_widget-user_menu-logout_button')?.addEventListener('click', () => {\r\n logoutUserDoboard(this.params.projectToken, this.params.accountId).then(() => {this.hide()});\r\n }) || '';\r\n\r\n document.getElementById('addNewTaskButton')?.addEventListener('click', () => {\r\n spotFixShowWidget();\r\n }) || '';\r\n\r\n document.getElementById('maximizeWidgetContainer')?.addEventListener('click', () => {\r\n const container = document.querySelector('.doboard_task_widget-container');\r\n\r\n if(+localStorage.getItem('maximize') && container.classList.contains('doboard_task_widget-container-maximize')){\r\n localStorage.setItem('maximize', '0');\r\n container.classList.remove('doboard_task_widget-container-maximize');\r\n } else {\r\n localStorage.setItem('maximize', '1');\r\n container.classList.add('doboard_task_widget-container-maximize');\r\n }\r\n }) || '';\r\n\r\n document.querySelector('#doboard_task_widget-user_menu-signlog_button')?.addEventListener('click', () => {\r\n spotFixShowWidget();\r\n }) || '';\r\n\r\n document.querySelector('#spotfix_back_button')?.addEventListener('click', () => {\r\n this.createWidgetElement(this.type_name)\r\n }) || '';\r\n\r\n return widgetContainer;\r\n }\r\n\r\n bindIssuesClick() {\r\n document.querySelectorAll('.issue-item').forEach(item => {\r\n item.addEventListener('click', async () => {\r\n let nodePath = null;\r\n try {\r\n nodePath = JSON.parse(item.getAttribute('data-node-path'));\r\n } catch (error) {\r\n nodePath = null;\r\n }\r\n if (nodePath) {\r\n spotFixScrollToNodePath(nodePath);\r\n }\r\n this.currentActiveTaskId = item.getAttribute('data-task-id');\r\n await this.showOneTask();\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Show one task\r\n *\r\n * @return {Promise}\r\n *\r\n */\r\n async showOneTask() {\r\n await this.createWidgetElement('concrete_issue');\r\n const taskHighlightData = this.getTaskHighlightData(this.currentActiveTaskId)\r\n\r\n if (taskHighlightData) {\r\n spotFixRemoveHighlights();\r\n spotFixHighlightElements([taskHighlightData], this)\r\n this.positionWidgetContainer();\r\n }\r\n\r\n hideContainersSpinner(false);\r\n }\r\n\r\n /**\r\n * Load the template\r\n *\r\n * @param templateName\r\n * @param variables\r\n * @return {string}\r\n * @ToDo have to refactor templates loaded method: need to be templates included into the bundle\r\n *\r\n */\r\n loadTemplate(templateName, variables = {}) {\r\n let template = SpotFixTemplatesLoader.getTemplateCode(templateName);\r\n\r\n for (const [key, value] of Object.entries(variables)) {\r\n const placeholder = `{{${key}}}`;\r\n let replacement;\r\n\r\n // 1) For attributes we MUST use escapeHtml!\r\n // 2) Only for HTML inserts we must clean data by ksesFilter\r\n // Check if placeholder is used in an attribute context\r\n if (this.isPlaceholderInAttribute(template, placeholder)) {\r\n // For attributes, use escapeHtml to prevent XSS\r\n replacement = this.escapeHtml(String(value));\r\n } else {\r\n // For HTML content, use ksesFilter to sanitize HTML\r\n replacement = ksesFilter(String(value), {template: templateName, imgFilter: true});\r\n }\r\n\r\n template = template.replaceAll(placeholder, replacement);\r\n }\r\n\r\n return ksesFilter(template, {template: templateName});\r\n }\r\n\r\n /**\r\n * Check if a placeholder is used inside an HTML attribute\r\n * @param {string} template - The template string\r\n * @param {string} placeholder - The placeholder to check (e.g., \"{{key}}\")\r\n * @return {boolean} - True if placeholder is in an attribute context\r\n */\r\n isPlaceholderInAttribute(template, placeholder) {\r\n // Escape special regex characters in placeholder\r\n const escapedPlaceholder = placeholder.replace(/[{}]/g, '\\\\$&');\r\n\r\n // Pattern to match attribute=\"...\" or attribute='...' containing the placeholder\r\n // This regex looks for: word characters (attribute name) = \" or ' followed by content including the placeholder\r\n // Matches patterns like: src=\"{{key}}\", class=\"{{key}}\", style=\"{{key}}\", etc.\r\n const attributePattern = new RegExp(\r\n `[\\\\w-]+\\\\s*=\\\\s*[\"'][^\"']*${escapedPlaceholder}[^\"']*[\"']`,\r\n 'g'\r\n );\r\n\r\n // Check if placeholder appears in any attribute context\r\n // If it does, we'll use escapeHtml for all occurrences (safer approach)\r\n return attributePattern.test(template);\r\n }\r\n\r\n escapeHtml = (unsafe) => {\r\n return unsafe\r\n .replace(/&/g, \"&\")\r\n .replace(//g, \">\")\r\n .replace(/\"/g, \""\")\r\n .replace(/'/g, \"'\");\r\n };\r\n\r\n async getTaskCount() {\r\n if (!localStorage.getItem('spotfix_session_id')) {\r\n return {};\r\n }\r\n\r\n const projectToken = this.params.projectToken;\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n\r\n const tasksCountLS = localStorage.getItem('spotfix_tasks_count');\r\n\r\n let tasksCount;\r\n\r\n if(tasksCountLS !== 0 && !tasksCountLS){\r\n const tasks = await getTasksDoboard(projectToken, sessionId, this.params.accountId, this.params.projectId);\r\n const filteredTasks = tasks.filter(task => {\r\n return task.taskMeta;\r\n });\r\n tasksCount = filteredTasks.length;\r\n } else tasksCount = tasksCountLS;\r\n\r\n const taskCountElement = document.getElementById('doboard_task_widget-task_count');\r\n if ( taskCountElement ) {\r\n taskCountElement.innerText = ksesFilter(tasksCount);\r\n taskCountElement.classList.remove('hidden');\r\n }\r\n }\r\n\r\n /**\r\n * Bind events to the widget\r\n */\r\n /*bindEvents() {\r\n this.submitButton.addEventListener('click', () => this.submitTask());\r\n }*/\r\n\r\n /**\r\n * Submit the task\r\n */\r\n async submitTask(taskDetails) {\r\n if (!localStorage.getItem('spotfix_session_id')) {\r\n await registerUser(taskDetails)(this.registrationShowMessage);\r\n if ( taskDetails.userPassword ) {\r\n await loginUser(taskDetails)(this.registrationShowMessage);\r\n }\r\n }\r\n\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n\r\n if ( ! sessionId ) {\r\n // @ToDo move this return in register block code\r\n return {needToLogin: true};\r\n }\r\n return await handleCreateTask(sessionId, taskDetails);\r\n }\r\n\r\n /**\r\n * Hide the widget\r\n */\r\n hide() {\r\n spotFixRemoveHighlights();\r\n this.createWidgetElement('wrap');\r\n\r\n }\r\n\r\n wrapElementWithSpotfixHighlight(element) {\r\n const newElement = element.cloneNode();\r\n const wrapper = document.createElement('span');\r\n wrapper.className = 'doboard_task_widget-text_selection image-highlight';\r\n\r\n element.insertAdjacentElement('beforebegin', wrapper);\r\n wrapper.appendChild(newElement);\r\n\r\n return wrapper;\r\n }\r\n\r\n /**\r\n * Get task spot data for highlighting.\r\n * @param {string|int} taskIdToSearch\r\n * @returns {object|null}\r\n */\r\n getTaskHighlightData(taskIdToSearch) {\r\n const currentTaskData = this.allTasksData.find((element) => element.taskId.toString() === taskIdToSearch.toString());\r\n if (currentTaskData && currentTaskData.taskMeta !== undefined) {\r\n let currentTaskSpotData = null;\r\n try {\r\n currentTaskSpotData = JSON.parse(currentTaskData.taskMeta);\r\n } catch (error) {\r\n currentTaskSpotData = null;\r\n }\r\n if (currentTaskSpotData !== null && typeof currentTaskSpotData === 'object') {\r\n return currentTaskSpotData;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n bindWidgetInputsInteractive() {\r\n // Customising placeholders\r\n const inputs = document.querySelectorAll('.doboard_task_widget-field');\r\n inputs.forEach(input => {\r\n if (input.value) {\r\n input.classList.add('has-value');\r\n }\r\n\r\n input.addEventListener('input', () => {\r\n if (input.value) {\r\n input.classList.add('has-value');\r\n } else {\r\n input.classList.remove('has-value');\r\n }\r\n });\r\n\r\n input.addEventListener('blur', () => {\r\n if (!input.value) {\r\n input.classList.remove('has-value');\r\n }\r\n });\r\n });\r\n\r\n // Customising accordion dropdown\r\n const accordionController = document.querySelector('.doboard_task_widget-login span');\r\n if ( accordionController ) {\r\n const context = this;\r\n accordionController.addEventListener('click', function() {\r\n this.closest('.doboard_task_widget-login').classList.toggle('active');\r\n // Scroll\r\n context.positionWidgetContainer();\r\n setTimeout(() => {\r\n const contentContainer = document.querySelector('.doboard_task_widget-content');\r\n contentContainer.scrollTo({\r\n top: contentContainer.scrollHeight,\r\n behavior: 'smooth'\r\n });\r\n }, 0);\r\n });\r\n }\r\n\r\n window.addEventListener('scroll', this.handleScroll.bind(this));\r\n window.addEventListener('resize', this.handleResize.bind(this));\r\n }\r\n\r\n registrationShowMessage(messageText, type = 'error') {\r\n const titleSpan = document.getElementById('doboard_task_widget-error_message-header');\r\n const messageDiv = document.getElementById('doboard_task_widget-error_message');\r\n const messageWrap = document.querySelector('.doboard_task_widget-message-wrapper');\r\n\r\n if (typeof messageText === 'string' && messageDiv !== null && messageWrap !== null) {\r\n messageDiv.innerText = ksesFilter(messageText);\r\n messageWrap.classList.remove('hidden');\r\n messageDiv.classList.remove('doboard_task_widget-notice_message', 'doboard_task_widget-error_message');\r\n if (type === 'notice') {\r\n titleSpan.innerText = ksesFilter('');\r\n messageWrap.classList.add('doboard_task_widget-notice_message');\r\n messageDiv.style.color = '#2a5db0';\r\n } else {\r\n titleSpan.innerText = ksesFilter('Registration error');\r\n messageWrap.classList.add('doboard_task_widget-error_message');\r\n messageDiv.style.color = 'red';\r\n }\r\n }\r\n }\r\n\r\n positionWidgetContainer() {\r\n const selection = document.querySelector('.doboard_task_widget-text_selection');\r\n const widget = document.querySelector('.doboard_task_widget')\r\n const widgetCreateIssue = document.querySelector('.doboard_task_widget-content.doboard_task_widget-create_issue')\r\n const widgetConcreteIssue = document.querySelector('.doboard_task_widget-concrete_issues-container')\r\n if ( ! ( ( widgetCreateIssue || widgetConcreteIssue ) && selection ) ) {\r\n // Skip if the widget is closed or highlight not exist\r\n return;\r\n }\r\n\r\n const scrollY = window.scrollY;\r\n const viewportHeight = window.innerHeight;\r\n\r\n const selectionAbsoluteTop = selection.getBoundingClientRect().top + scrollY;\r\n\r\n const widgetHeight = widget.offsetHeight;\r\n\r\n let top;\r\n\r\n // Check selection position\r\n if (selectionAbsoluteTop - scrollY < 0) {\r\n // 1) The selection is above the viewport - stuck the widget on the top\r\n top = 10;\r\n } else if (selectionAbsoluteTop - scrollY > viewportHeight) {\r\n // 2) The selection is below the viewport - stuck the widget on the bottom\r\n top = viewportHeight - widgetHeight - 10;\r\n } else {\r\n // 3) The selection is on viewport - the widget aligned against the selection\r\n top = selectionAbsoluteTop - scrollY\r\n if ( selectionAbsoluteTop - scrollY > viewportHeight - widgetHeight ) {\r\n // 3.1) The selection is on viewport but is below than widget height - stuck the widget on the bottom\r\n top = viewportHeight - widgetHeight - 10;\r\n }\r\n }\r\n\r\n widget.style.top = `${top}px`;\r\n widget.style.bottom = 'auto';\r\n }\r\n\r\n handleScroll() {\r\n clearTimeout(this.scrollTimeout);\r\n this.scrollTimeout = setTimeout(() => {\r\n this.positionWidgetContainer();\r\n }, 10);\r\n }\r\n\r\n handleResize() {\r\n clearTimeout(this.resizeTimeout);\r\n this.resizeTimeout = setTimeout(() => {\r\n this.positionWidgetContainer();\r\n }, 100);\r\n }\r\n\r\n /**\r\n * Check nodePath, selectedData against page source and return is the provided nodePath is correct and can be highlighted\r\n * @param taskData\r\n * @return {boolean}\r\n */\r\n isSpotHaveToBeHighlighted(taskData) {\r\n return true;\r\n }\r\n\r\n sanitizeNodePath(nodePath) {\r\n let str = Array.isArray(nodePath) ? JSON.stringify(nodePath) : String(nodePath);\r\n // Allow only digits, commas, spaces, and square brackets\r\n if (/^[\\[\\]0-9,\\s]*$/.test(str)) {\r\n return str;\r\n }\r\n return '';\r\n}\r\n}\r\n\nvar spotFixShowDelayTimeout = null;\r\nconst SPOTFIX_DEBUG = false;\r\nconst SPOTFIX_SHOW_DELAY = 1000;\r\n\r\nif( document.readyState !== 'loading' ) {\r\n document.addEventListener('spotFixLoaded', spotFixInit);\r\n} else {\r\n document.addEventListener('DOMContentLoaded', spotFixInit);\r\n}\r\n\r\nfunction spotFixInit() {\r\n new SpotFixSourcesLoader();\r\n new CleanTalkWidgetDoboard({}, 'wrap');\r\n loadBotDetector()\r\n}\r\n\r\nfunction loadBotDetector() {\r\nif (document.querySelector('script[src=\"https://moderate.cleantalk.org/ct-bot-detector-wrapper.js\"]') ||\r\n document.getElementById('ct-bot-detector-script')) {\r\n return;\r\n }\r\n\r\n const script = document.createElement('script');\r\n script.src = 'https://moderate.cleantalk.org/ct-bot-detector-wrapper.js';\r\n script.async = true;\r\n script.id = 'ct-bot-detector-script';\r\n document.head.appendChild(script);\r\n}\r\n\r\ndocument.addEventListener('selectionchange', function(e) {\r\n // Do not run widget for non-document events (i.e. inputs focused)\r\n\r\n if (e.target !== document) {\r\n return;\r\n }\r\n\r\n const isWrapReviewWidgetExists = !!(document.getElementsByClassName('wrap_review')[0]);\r\n const sel = document.getSelection();\r\n\r\n if ((!sel || sel.toString() === \"\") && isWrapReviewWidgetExists) {\r\n new CleanTalkWidgetDoboard({}, 'wrap')\r\n return;\r\n }\r\n\r\n if (spotFixShowDelayTimeout) {\r\n clearTimeout(spotFixShowDelayTimeout);\r\n }\r\n\r\n spotFixShowDelayTimeout = setTimeout(() => {\r\n const selection = window.getSelection();\r\n if (\r\n selection.type === 'Range'\r\n ) {\r\n // Check if selection is inside the widget\r\n let anchorNode = selection.anchorNode;\r\n let focusNode = selection.focusNode;\r\n if (spotFixIsInsideWidget(anchorNode) || spotFixIsInsideWidget(focusNode)) {\r\n return;\r\n }\r\n const selectedData = spotFixGetSelectedData(selection);\r\n\r\n if ( selectedData ) {\r\n // spotFixOpenWidget(selectedData, 'create_issue');\r\n spotFixOpenWidget(selectedData, 'wrap_review');\r\n }\r\n }\r\n }, SPOTFIX_SHOW_DELAY);\r\n});\r\n\r\n\r\n/**\r\n * Shows the spot fix widget.\r\n */\r\nfunction spotFixShowWidget() {\r\n new CleanTalkWidgetDoboard(null, 'create_issue');\r\n}\r\n\r\n/**\r\n * Check if a node is inside the task widget.\r\n * @param {*} node\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsInsideWidget(node) {\r\n if (!node) return false;\r\n let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n while (el) {\r\n if (el.classList && el.classList.contains('doboard_task_widget')) {\r\n return true;\r\n }\r\n el = el.parentElement;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Open the widget to create a task.\r\n * @param {*} selectedData\r\n * @param {*} type\r\n */\r\nfunction spotFixOpenWidget(selectedData, type) {\r\n if (selectedData) {\r\n new CleanTalkWidgetDoboard(selectedData, type);\r\n }\r\n}\r\n\r\n/**\r\n * Write message into the console.\r\n *\r\n * @param {string} message\r\n */\r\nfunction spotFixDebugLog(message) {\r\n if ( SPOTFIX_DEBUG ) {\r\n console.log(message);\r\n }\r\n}\r\n\r\nfunction hideContainersSpinner() {\r\n const spinners = document.getElementsByClassName('doboard_task_widget-spinner_wrapper_for_containers');\r\n if (spinners.length > 0) {\r\n for (let i = 0; i < spinners.length ; i++) {\r\n spinners[i].style.display = 'none';\r\n }\r\n }\r\n const containerClassesToShow = ['doboard_task_widget-all_issues-container', 'doboard_task_widget-concrete_issues-container'];\r\n for (let i = 0; i < containerClassesToShow.length ; i++) {\r\n const containers = document.getElementsByClassName(containerClassesToShow[i]);\r\n if (containers.length > 0) {\r\n for (let i = 0; i < containers.length ; i++) {\r\n containers[i].style.display = 'block';\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction getTaskFullDetails(tasksDetails, taskId) {\r\n const comments = tasksDetails.comments.filter(comment => {\r\n return comment?.taskId?.toString() === taskId?.toString()\r\n });\r\n const users = tasksDetails.users;\r\n // Last comment\r\n let lastComment = comments.length > 0 ? comments[0] : null;\r\n // Author of the last comment\r\n let author = null;\r\n if (lastComment && users && users.length > 0) {\r\n author = users.find(u => String(u.user_id) === String(lastComment.userId));\r\n }\r\n // Format date\r\n let date = '', time = '';\r\n if (lastComment) {\r\n const dt = formatDate(lastComment.commentDate);\r\n date = dt.date;\r\n time = dt.time;\r\n }\r\n // Get the avatar and the name through separate functions\r\n let avatarSrc = getAvatarSrc(author);\r\n let authorName = getAuthorName(author);\r\n\r\n return {\r\n taskId: taskId,\r\n taskAuthorAvatarImgSrc: avatarSrc,\r\n taskAuthorName: authorName,\r\n lastMessageText: lastComment ? lastComment.commentBody : 'No messages yet',\r\n lastMessageTime: time,\r\n issueTitle: comments.length > 0 ? comments[0].issueTitle : 'No Title',\r\n issueComments: comments\r\n .sort((a, b) => {\r\n return new Date(a.commentDate) - new Date(b.commentDate);\r\n })\r\n .map(comment => {\r\n const {date, time} = formatDate(comment.commentDate);\r\n let author = null;\r\n if (users && users.length > 0) {\r\n author = users.find(u => String(u.user_id) === String(comment.userId));\r\n }\r\n return {\r\n commentAuthorAvatarSrc: getAvatarSrc(author),\r\n commentAuthorName: getAuthorName(author),\r\n commentBody: comment.commentBody,\r\n commentDate: date,\r\n commentTime: time,\r\n commentUserId: comment.userId || 'Unknown User',\r\n };\r\n })\r\n };\r\n}\r\n\r\nfunction getAvatarData(authorDetails) {\r\n let avatarStyle;\r\n let avatarCSSClass;\r\n let taskAuthorInitials =\r\n authorDetails.taskAuthorName && authorDetails.taskAuthorName != 'Anonymous'\r\n ? authorDetails.taskAuthorName.trim().charAt(0).toUpperCase()\r\n : null;\r\n let initialsClass = 'doboard_task_widget-avatar-initials';\r\n if (authorDetails.taskAuthorAvatarImgSrc === null && taskAuthorInitials !== null) {\r\n avatarStyle = 'display: flex;background-color: #f8de7e;justify-content: center;align-items: center;';\r\n avatarCSSClass = 'doboard_task_widget-avatar_container';\r\n }\r\n if (authorDetails.taskAuthorAvatarImgSrc === null && taskAuthorInitials === null) {\r\n avatarStyle = `background-image:url(\\'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');`;\r\n avatarCSSClass = 'doboard_task_widget-avatar_container';\r\n initialsClass += ' doboard_task_widget-hidden_element';\r\n }\r\n if (authorDetails.taskAuthorAvatarImgSrc !== null) {\r\n avatarStyle = `background-image:url(\\'${authorDetails.taskAuthorAvatarImgSrc}\\');`;\r\n avatarCSSClass = 'doboard_task_widget-avatar_container';\r\n initialsClass = 'doboard_task_widget-hidden_element';\r\n }\r\n return {\r\n avatarStyle: avatarStyle,\r\n avatarCSSClass: avatarCSSClass,\r\n taskAuthorInitials: taskAuthorInitials,\r\n initialsClass: initialsClass\r\n }\r\n}\r\n\r\n/**\r\n * Return first found updated task ID or false if no tasks were updated\r\n * @param allTasksData\r\n * @returns {string[]|false}\r\n */\r\nfunction isAnyTaskUpdated(allTasksData) {\r\n let result = false;\r\n\r\n const updatedtasksIDS = [];\r\n\r\n for (let i = 0; i < allTasksData.length; i++) {\r\n const currentStateOfTask = allTasksData[i];\r\n const issuerId = localStorage.getItem('spotfix_user_id');\r\n if (\r\n currentStateOfTask.taskId &&\r\n currentStateOfTask.taskLastUpdate &&\r\n currentStateOfTask.taskCreatorTaskUser.toString() === issuerId.toString()\r\n ) {\r\n result = storageCheckTaskUpdate(currentStateOfTask.taskId, currentStateOfTask.taskLastUpdate);\r\n if (result) {\r\n updatedtasksIDS.push(currentStateOfTask.taskId.toString());\r\n }\r\n }\r\n }\r\n\r\n return updatedtasksIDS.length === 0 ? false : updatedtasksIDS;\r\n}\r\n\r\n/**\r\n * Check if any of the tasks has updates from site owner (not from the current user and not anonymous)\r\n * @returns {Promise}\r\n */\r\nasync function checkIfTasksHasSiteOwnerUpdates(allTasksData, params) {\r\n const updatedTaskIDs = isAnyTaskUpdated(allTasksData);\r\n let result = false;\r\n if (!updatedTaskIDs) {\r\n return false;\r\n }\r\n for (let i = 0; i < updatedTaskIDs.length; i++) {\r\n const updatedTaskId = updatedTaskIDs[i];\r\n if (typeof updatedTaskId === 'string') {\r\n const updatedTaskData = await getTasksFullDetails(params, [updatedTaskId]);\r\n if (updatedTaskData.comments) {\r\n const lastMessage = updatedTaskData.comments[0];\r\n if (\r\n lastMessage.commentUserId !== undefined &&\r\n lastMessage.commentUserId !== localStorage.getItem('spotfix_user_id') &&\r\n lastMessage.commentAuthorName !== 'Anonymous'\r\n ) {\r\n storageAddUnreadUpdateForTaskID(updatedTaskId);\r\n result = true;\r\n }\r\n }\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Check if the selection is correct - do not allow to select all page, or several different nesting nodes, or something else\r\n * @param selection\r\n * @return {boolean}\r\n */\r\nfunction isSelectionCorrect(selection) {\r\n return true;\r\n}\r\n\r\n/**\r\n * Sanitize HTML\r\n * @param {*} html\r\n * @param {*} options\r\n * @returns\r\n */\r\nfunction ksesFilter(html, options = false) {\r\n let allowedTags = {\r\n a: true,\r\n b: true,\r\n i: true,\r\n strong: true,\r\n em: true,\r\n ul: true,\r\n ol: true,\r\n li: true,\r\n p: true,\r\n s: true,\r\n br: true,\r\n span: true,\r\n blockquote: true,\r\n pre: true,\r\n div: true,\r\n img: true,\r\n input: true,\r\n label: true,\r\n textarea: true,\r\n button: true,\r\n blockquote: true,\r\n pre: true,\r\n details: true,\r\n summary: true,\r\n };\r\n let allowedAttrs = {\r\n a: ['href', 'title', 'target', 'rel', 'style', 'class'],\r\n span: ['style', 'class', 'id'],\r\n p: ['style', 'class'],\r\n div: ['style', 'class', 'id', 'data-node-path', 'data-task-id'],\r\n img: ['src', 'alt', 'title', 'class', 'style', 'width', 'height'],\r\n input: ['type', 'class', 'style', 'id', 'multiple', 'accept', 'value'],\r\n label: ['for', 'class', 'style'],\r\n textarea: ['class', 'id', 'style', 'rows', 'cols', 'readonly', 'required', 'name'],\r\n button: ['type', 'class', 'style', 'id'],\r\n details: ['class', 'style', 'open'],\r\n summary: ['class', 'style'],\r\n };\r\n\r\n if (options && options.template === 'list_issues') {\r\n allowedTags = { ...allowedTags, br: false };\r\n }\r\n\r\n const parser = new DOMParser();\r\n const doc = parser.parseFromString(html, 'text/html');\r\n function clean(node) {\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const tag = node.tagName.toLowerCase();\r\n\r\n if (options) {\r\n if (allowedTags[tag]) {\r\n // Special handling for images in 'concrete_issue_day_content' template (wrap img in link always)\r\n if (tag === 'img' && options.template === 'concrete_issue_day_content' && options.imgFilter) {\r\n const src = node.getAttribute('src') || '';\r\n const alt = node.getAttribute('alt') || '[image]';\r\n const link = doc.createElement('a');\r\n link.href = src;\r\n link.target = '_blank';\r\n link.className = 'doboard_task_widget-img-link';\r\n const img = doc.createElement('img');\r\n img.src = src;\r\n img.alt = alt;\r\n img.className = 'doboard_task_widget-comment_body-img-strict';\r\n link.appendChild(img);\r\n node.parentNode.insertBefore(link, node);\r\n node.remove();\r\n return;\r\n }\r\n }\r\n\r\n if (!allowedTags[tag]) {\r\n // Special handling for images in 'list_issues' template\r\n if (tag === 'img' && options.template === 'list_issues' && options.imgFilter) {\r\n const src = node.getAttribute('src') || '';\r\n const alt = node.getAttribute('alt') || '[image]';\r\n const link = doc.createElement('a');\r\n link.href = src;\r\n link.target = '_blank';\r\n link.textContent = alt;\r\n node.parentNode.insertBefore(link, node);\r\n }\r\n node.remove();\r\n return;\r\n }\r\n }\r\n\r\n // Remove disallowed attributes\r\n [...node.attributes].forEach(attr => {\r\n const attrName = attr.name.toLowerCase();\r\n if (!allowedAttrs[tag]?.includes(attrName) ||\r\n attrName.startsWith('on') || // Remove event handlers\r\n attr.value.toLowerCase().includes('javascript:')) {\r\n node.removeAttribute(attr.name);\r\n }\r\n });\r\n }\r\n // Recursively clean children\r\n [...node.childNodes].forEach(clean);\r\n }\r\n [...doc.body.childNodes].forEach(clean);\r\n return doc.body.innerHTML;\r\n}\r\n\nlet spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:\"\";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget-header-icons{display:flex}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:\"\";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:\"\";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:\"\";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:\"wght\" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E\") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E\") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:\"\"}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:\"\";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`;\n/**\r\n * SELECTION will be grouped into three types:\r\n * 1 - Simple text within a single tag\r\n * 2 - Image tags\r\n * 3 - Any tag containing nested content\r\n * Each type will be processed differently.\r\n */\r\nconst SPOTFIX_SELECTION_TYPE_TEXT = 'text';\r\nconst SPOTFIX_SELECTION_TYPE_IMG = 'image';\r\nconst SPOTFIX_SELECTION_TYPE_ELEMENT = 'element';\r\n\r\n/**\r\n * Determines the type of selection\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {string|null} Selection type\r\n */\r\nfunction spotFixGetSelectionType(selection) {\r\n const range = selection.getRangeAt(0);\r\n const commonAncestor = range.commonAncestorContainer;\r\n\r\n // Case 1: Image selection\r\n if (spotFixGetSelectedImage(selection)) {\r\n return SPOTFIX_SELECTION_TYPE_IMG;\r\n }\r\n\r\n // Case 2: Element with nested content\r\n if (commonAncestor.nodeType === Node.ELEMENT_NODE &&\r\n commonAncestor.childNodes.length > 1 &&\r\n range.toString().trim() === '' &&\r\n range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE) {\r\n return SPOTFIX_SELECTION_TYPE_ELEMENT;\r\n }\r\n\r\n // Case 3: Simple text\r\n const hasTextContent = range.toString().trim().length > 0;\r\n const isTextNode = commonAncestor.nodeType === Node.TEXT_NODE;\r\n const isCollapsed = range.collapsed;\r\n\r\n if (hasTextContent && (isTextNode || !isCollapsed)) {\r\n return SPOTFIX_SELECTION_TYPE_TEXT;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extracts selection data from DOM Selection object\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {Object|null} Selection data with text, positions, URL and node path OR null (nothing)\r\n */\r\nfunction spotFixGetSelectedData(selection) {\r\n // Prechecks:\r\n // Selection not provided\r\n if (!selection) {spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection not provided`'); return null; }\r\n // Range not provided\r\n if (selection.rangeCount === 0) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Range not provided`'); return null; }\r\n // Several ranges provided\r\n if (selection.rangeCount > 1) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Several ranges provided`'); return null; }\r\n\r\n const range = selection.getRangeAt(0);\r\n // Selection must be within a single DOM element.\r\n if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }\r\n\r\n // FIRST - check selection type\r\n const selectionType = spotFixGetSelectionType(selection);\r\n\r\n // Selection type not determined\r\n if (!selectionType) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection type not determined`'); return null; }\r\n\r\n // SECOND - generate selectedData for each selectionType\r\n let selectedText = '';\r\n let startSelectPosition = 0;\r\n let endSelectPosition = 0;\r\n let nodePath = '';\r\n let imageUrl = '';\r\n\r\n const commonNode = range.commonAncestorContainer;\r\n\r\n switch (selectionType) {\r\n case SPOTFIX_SELECTION_TYPE_TEXT:\r\n if (range.toString().trim().length === 0) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection text is empty`');\r\n return null;\r\n }\r\n const commonNodeElement = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n selectedText = range.toString();\r\n startSelectPosition = range.startOffset;\r\n endSelectPosition = range.endOffset;\r\n if ( startSelectPosition === 0 && selectedText.length > endSelectPosition ) {\r\n endSelectPosition = selectedText.length;\r\n }\r\n nodePath = spotFixCalculateNodePath(commonNodeElement);\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_IMG:\r\n const imgElement = range.startContainer;\r\n const selectedImage = spotFixGetSelectedImage(selection);\r\n selectedText = `Image (${selectedImage.alt ? selectedImage.alt : 'no description'})`;\r\n nodePath = spotFixCalculateNodePath(selectedImage);\r\n // For images, positions represent the image element position in parent\r\n startSelectPosition = Array.from(imgElement.parentNode.children).indexOf(imgElement);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_ELEMENT:\r\n const element = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n if (element.childNodes.length <= 1) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection have not inner data`');\r\n return null;\r\n }\r\n selectedText = element.textContent || '';\r\n nodePath = spotFixCalculateNodePath(element);\r\n // For elements, positions represent the element's position in parent\r\n startSelectPosition = Array.from(element.parentNode.children).indexOf(element);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n }\r\n\r\n // Get page URL\r\n const pageURL = window.location.href;\r\n\r\n return {\r\n startSelectPosition,\r\n endSelectPosition,\r\n selectedText: selectedText.trim(),\r\n pageURL,\r\n nodePath,\r\n selectionType,\r\n imageUrl: selectionType === SPOTFIX_SELECTION_TYPE_IMG ? imageUrl : ''\r\n };\r\n}\r\n\r\n/**\r\n * Highlight elements.\r\n * @param {[object]} spotsToBeHighlighted\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightElements(spotsToBeHighlighted, widgetInstance) {\r\n\r\n if (spotsToBeHighlighted.length === 0) return;\r\n\r\n const elementsMap = new Map();\r\n\r\n // Grouping elements with validation\r\n spotsToBeHighlighted.forEach(spot => {\r\n // nodePath validating: is array\r\n if (!spot?.nodePath || !Array.isArray(spot?.nodePath)) {\r\n spotFixDebugLog('Invalid spot: missing or invalid nodePath: ' + spot);\r\n return;\r\n }\r\n\r\n // nodePath validating: is valid indexes list\r\n if (!this.spotFixIsValidNodePath(spot.nodePath)) {\r\n spotFixDebugLog('Invalid nodePath format: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n const element = spotFixRetrieveNodeFromPath(spot.nodePath);\r\n if (!element) {\r\n spotFixDebugLog('Element not found for path: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n if ( ! spot.selectionType ) {\r\n // @ToDo need to apply backward capability here\r\n // just `spot.selectionType = 'text';` is not able, this opens ability to unauthorized modify website content\r\n spotFixDebugLog('Selection type is not provided.');\r\n return;\r\n }\r\n\r\n // selectionType parameter validating\r\n if (\r\n spot.selectionType &&\r\n ![\r\n SPOTFIX_SELECTION_TYPE_TEXT,\r\n SPOTFIX_SELECTION_TYPE_IMG,\r\n SPOTFIX_SELECTION_TYPE_ELEMENT\r\n ].includes(spot.selectionType)\r\n ) {\r\n spotFixDebugLog('Invalid selection type: ' + spot.selectionType);\r\n return;\r\n }\r\n\r\n if (!elementsMap.has(element)) {\r\n elementsMap.set(element, []);\r\n }\r\n elementsMap.get(element).push(spot);\r\n });\r\n\r\n elementsMap.forEach((spots, element) => {\r\n const selectionType = spots[0].selectionType;\r\n\r\n // MAIN LOGIC: highlight for the different types\r\n switch (selectionType) {\r\n case 'image':\r\n this.spotFixHighlightImageElement(element);\r\n break;\r\n\r\n case 'element':\r\n this.spotFixHighlightNestedElement(element);\r\n break;\r\n\r\n case 'text':\r\n this.spotFixHighlightTextInElement(element, spots, widgetInstance);\r\n break;\r\n\r\n default:\r\n spotFixDebugLog('Unknown selection type: ' + selectionType);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Highlight image element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightImageElement(element) {\r\n if (element.tagName !== 'IMG') {\r\n spotFixDebugLog('Expected IMG element for image highlight, got: ' + element.tagName);\r\n return;\r\n }\r\n element.classList.add('doboard_task_widget-image_selection');\r\n}\r\n\r\n/**\r\n * Highlight nested element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightNestedElement(element) {\r\n element.classList.add('doboard_task_widget-element_selection');\r\n}\r\n\r\n/**\r\n * Highlight text in element with span wrapping\r\n * @param {Element} element\r\n * @param {Array} spots\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightTextInElement(element, spots,widgetInstance) {\r\n let tooltipTitleText = '';\r\n if (spots[0].isFixed) {\r\n tooltipTitleText = `This issue already fixed.`;\r\n } else {\r\n tooltipTitleText = `We are already working on this issue.`;\r\n }\r\n\r\n const tooltip = `
\r\n \r\n \r\n
${tooltipTitleText}
\r\n
You can see history Here
\r\n
\r\n
`;\r\n\r\n const spotfixHighlightOpen = `${tooltip}`;\r\n const spotfixHighlightClose = ``;\r\n\r\n let text = element.textContent;\r\n const spotSelectedText = spots[0].selectedText;\r\n\r\n // meta.selectedText can not be empty string\r\n if ( ! spotSelectedText ) {\r\n spotFixDebugLog('Provided metadata is invalid.');\r\n return;\r\n }\r\n\r\n const markers = [];\r\n\r\n // Mark positions for inserting\r\n spots.forEach(spot => {\r\n // Validating positions\r\n const startPos = parseInt(spot.startSelectPosition) || 0;\r\n const endPos = parseInt(spot.endSelectPosition) || 0;\r\n\r\n if (startPos < 0 || endPos > text.length || startPos > endPos) {\r\n spotFixDebugLog('Invalid text positions: ' + spot);\r\n return;\r\n }\r\n\r\n markers.push({ position: startPos, type: 'start' });\r\n markers.push({ position: endPos, type: 'end' });\r\n });\r\n\r\n if (markers.length === 0) return;\r\n\r\n // Sort markers backward\r\n markers.sort((a, b) => b.position - a.position);\r\n\r\n // Check here that element (from meta.nodePath) contains same inner text as in meta.selectedText\r\n // Is the `text` in the element equal to the selected text `spotSelectedText`\r\n if ( text.slice(markers[1].position, markers[0].position) !== spotSelectedText ) {\r\n spotFixDebugLog('It is not allow to highlight element by provided metadata.');\r\n return;\r\n }\r\n\r\n let result = text;\r\n markers.forEach(marker => {\r\n const insertText = marker.type === 'start'\r\n ? spotfixHighlightOpen\r\n : spotfixHighlightClose;\r\n\r\n result = result.slice(0, marker.position) + insertText + result.slice(marker.position);\r\n });\r\n\r\n // Safety HTML insert\r\n try {\r\n element.innerHTML = ksesFilter(result);\r\n document.querySelectorAll('.doboard_task_widget-see-task').forEach(link => {\r\n link.addEventListener('click', (e) => {\r\n\r\n e.preventDefault();\r\n const classList = link.className.split(' ');\r\n const idClass = classList.find(cls => cls.includes('__task-id-'));\r\n let taskId = null;\r\n if (idClass) {\r\n taskId = idClass.split('__task-id-')[1];\r\n }\r\n if (taskId) {\r\n widgetInstance.currentActiveTaskId = taskId;\r\n widgetInstance.showOneTask();\r\n }\r\n });\r\n });\r\n } catch (error) {\r\n spotFixDebugLog('Error updating element content: ' + error);\r\n }\r\n}\r\n\r\n/**\r\n * Scroll to an element by tag, class, and text content\r\n * @param {array} path - The path to the element\r\n * @return {boolean} - True if the element was found and scrolled to, false otherwise\r\n */\r\nfunction spotFixScrollToNodePath(path) {\r\n const node = spotFixRetrieveNodeFromPath(path);\r\n if (node && node.scrollIntoView) {\r\n node.scrollIntoView({ behavior: 'smooth', block: 'center' });\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction spotFixRemoveHighlights() {\r\n const textSelectionclassName = 'doboard_task_widget-text_selection';\r\n const spans = document.querySelectorAll('.' + textSelectionclassName);\r\n const affectedParents = new Set(); // Track unique parents\r\n\r\n spans.forEach(span => {\r\n const parent = span.parentNode;\r\n affectedParents.add(parent); // Mark parent as affected\r\n const tooltip = span.querySelector('.doboard_task_widget-text_selection_tooltip');\r\n if (tooltip) tooltip.remove();\r\n\r\n // Move all child nodes out of the span and into the parent\r\n while (span.firstChild) {\r\n parent.insertBefore(span.firstChild, span);\r\n }\r\n parent.removeChild(span);\r\n });\r\n\r\n // Normalize all affected parents to merge adjacent text nodes\r\n affectedParents.forEach(parent => parent.normalize());\r\n\r\n const elementSelectionClassName = 'doboard_task_widget-element_selection';\r\n const elements = document.querySelectorAll(`.${elementSelectionClassName}`);\r\n elements.forEach(element => {\r\n element.classList.remove(elementSelectionClassName);\r\n });\r\n const imageSelectionClassName = 'doboard_task_widget-image_selection';\r\n const images = document.querySelectorAll(`.${imageSelectionClassName}`);\r\n images.forEach(element => {\r\n element.classList.remove(imageSelectionClassName);\r\n });\r\n}\r\n\r\n/**\r\n * Validate nodePath as array of indices\r\n * @param {Array} nodePath\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsValidNodePath(nodePath) {\r\n if (!Array.isArray(nodePath)) return false;\r\n if (nodePath.length === 0) return false;\r\n\r\n return nodePath.every(index => {\r\n return Number.isInteger(index) && index >= 0 && index < 1000;\r\n });\r\n}\r\n\r\n/**\r\n * Try to find selected image in selection.\r\n * @param selection\r\n * @returns {Node|*|null}\r\n */\r\nfunction spotFixGetSelectedImage(selection) {\r\n\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\r\n return null;\r\n }\r\n\r\n const range = selection.getRangeAt(0);\r\n\r\n // Is current end container IMG\r\n if (range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE &&\r\n range.startContainer.tagName === 'IMG') {\r\n return range.startContainer;\r\n }\r\n\r\n // Get img in the range\r\n const walker = document.createTreeWalker(\r\n range.commonAncestorContainer,\r\n NodeFilter.SHOW_ELEMENT,\r\n {\r\n acceptNode: function(node) {\r\n return node.tagName === 'IMG' &&\r\n spotFixIsElementInRange(node, range) ?\r\n NodeFilter.FILTER_ACCEPT :\r\n NodeFilter.FILTER_REJECT;\r\n }\r\n }\r\n );\r\n\r\n let imgNode = walker.nextNode();\r\n if (imgNode) {\r\n return imgNode;\r\n }\r\n\r\n // start/end containers\r\n const startElement = spotFixGetElementFromNode(range.startContainer);\r\n const endElement = spotFixGetElementFromNode(range.endContainer);\r\n\r\n // If selection starts on image\r\n if (startElement && startElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(startElement, range)) {\r\n return startElement;\r\n }\r\n\r\n if (endElement && endElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(endElement, range)) {\r\n return endElement;\r\n }\r\n\r\n // 4. Get closest IMG\r\n const nearbyElements = spotFixFindNearbyElements(range);\r\n for (const element of nearbyElements) {\r\n if (element.tagName === 'IMG') {\r\n return element;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction spotFixIsElementInRange(element, range) {\r\n const elementRange = document.createRange();\r\n elementRange.selectNode(element);\r\n return range.compareBoundaryPoints(Range.START_TO_START, elementRange) <= 0 &&\r\n range.compareBoundaryPoints(Range.END_TO_END, elementRange) >= 0;\r\n}\r\n\r\nfunction spotFixIsElementPartiallySelected(element, range) {\r\n const elementRect = element.getBoundingClientRect();\r\n const rangeRect = range.getBoundingClientRect();\r\n\r\n // bounding rectangles is crossed\r\n return !(elementRect.right < rangeRect.left ||\r\n elementRect.left > rangeRect.right ||\r\n elementRect.bottom < rangeRect.top ||\r\n elementRect.top > rangeRect.bottom);\r\n}\r\n\r\nfunction spotFixGetElementFromNode(node) {\r\n return node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n}\r\n\r\n/**\r\n * Find nearby elements in the range.\r\n * @param range\r\n * @returns {*[]}\r\n */\r\nfunction spotFixFindNearbyElements(range) {\r\n const elements = [];\r\n const container = range.commonAncestorContainer;\r\n\r\n // search elements\r\n const previousElement = container.previousElementSibling;\r\n const nextElement = container.nextElementSibling;\r\n\r\n if (previousElement) {\r\n elements.push(previousElement);\r\n }\r\n if (nextElement) {\r\n elements.push(nextElement);\r\n }\r\n\r\n // Also check child container\r\n if (container.nodeType === Node.ELEMENT_NODE) {\r\n const children = container.children;\r\n for (let i = 0; i < children.length; i++) {\r\n if (spotFixIsElementPartiallySelected(children[i], range)) {\r\n elements.push(children[i]);\r\n }\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Calculate the path of a DOM node\r\n *\r\n * @param {Node} node\r\n * @return {int[]}\r\n */\r\nfunction spotFixCalculateNodePath(node) {\r\n let path = [];\r\n while (node) {\r\n let index = 0;\r\n let sibling = node.previousSibling;\r\n while (sibling) {\r\n if (sibling.nodeType === 1) {\r\n index++;\r\n }\r\n sibling = sibling.previousSibling;\r\n }\r\n path.unshift(index);\r\n node = node.parentNode;\r\n }\r\n\r\n // Hard fix - need to remove first element to work correctly\r\n path.shift();\r\n\r\n return path;\r\n}\r\n\r\n/**\r\n * Retrieve a DOM node from a path\r\n *\r\n * @param {int[]} path\r\n * @return {*|null}\r\n */\r\nfunction spotFixRetrieveNodeFromPath(path) {\r\n // @ToDo check if the path is correct\r\n if ( ! path ) {\r\n return null;\r\n }\r\n\r\n let node = document;\r\n for (let i = 0; i < path.length; i++) {\r\n node = node.children[path[i]];\r\n if ( ! node ) {\r\n return null;\r\n }\r\n }\r\n return node;\r\n}\r\n\n/**\r\n * Return bool if widget is closed in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetWidgetIsClosed() {\r\n return localStorage.getItem('spotfix_widget_is_closed') === '1';\r\n}\r\n\r\n/**\r\n * Return bool if widget closed state is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageWidgetCloseIsSet() {\r\n return localStorage.getItem('spotfix_widget_is_closed') !== null;\r\n}\r\n\r\n/**\r\n * Save widget closed state\r\n * @param visible\r\n */\r\nfunction storageSetWidgetIsClosed(visible) {\r\n localStorage.setItem('spotfix_widget_is_closed', visible ? '1' : '0');\r\n}\r\n\r\n/**\r\n * Return bool if user is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetUserIsDefined() {\r\n return localStorage.getItem('spotfix_user_id') !== null;\r\n}\r\n\r\n/**\r\n * Save data for updates check\r\n * @param tasks\r\n */\r\nfunction storageSaveTasksUpdateData(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n\r\n tasks.forEach(task => {\r\n if (task.taskId && task.taskLastUpdate) {\r\n storedTasks[task.taskId] = {\r\n taskId: task.taskId,\r\n taskLastUpdate: task.taskLastUpdate\r\n };\r\n }\r\n });\r\n\r\n localStorage.setItem('spotfix_task_updates', JSON.stringify(storedTasks));\r\n}\r\n\r\nfunction storageSaveTasksCount(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n const count = tasks.filter(task => {\r\n return task.taskMeta;\r\n })?.length;\r\n\r\n localStorage.setItem('spotfix_tasks_count', `${count}`);\r\n}\r\n\r\n/**\r\n * Check if a specific task has been updated since last check\r\n * @param taskId\r\n * @param currentLastUpdate\r\n * @returns {boolean|null}\r\n */\r\nfunction storageCheckTaskUpdate(taskId, currentLastUpdate) {\r\n if (!taskId || !currentLastUpdate) {\r\n return null;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n const storedTask = storedTasks[taskId];\r\n\r\n if (!storedTask) {\r\n return false;\r\n }\r\n\r\n const storedUpdate = new Date(storedTask.taskLastUpdate);\r\n const currentUpdate = new Date(currentLastUpdate);\r\n return currentUpdate > storedUpdate;\r\n}\r\n\r\n/**\r\n * Add unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageAddUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n if (!storedUnread.includes(taskId)) {\r\n storedUnread.push(taskId);\r\n }\r\n\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Remove unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageRemoveUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n storedUnread = storedUnread.filter(id => id !== taskId);\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Check if there are any unread updates\r\n * @returns {boolean}\r\n */\r\nfunction storageTasksHasUnreadUpdates() {\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.length > 0;\r\n}\r\n\r\n/**\r\n * Check if a specific task has unread updates\r\n * @param taskId\r\n * @returns {boolean}\r\n */\r\nfunction storageProvidedTaskHasUnreadUpdates(taskId) {\r\n if (!taskId) {\r\n return false;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.includes(taskId.toString());\r\n}\r\n\r\nfunction storageSaveSpotfixVersion (version) {\r\n localStorage.setItem('spotfix_app_version', `${version}`);\r\n}\r\n\r\nfunction clearLocalstorageOnLogout () {\r\n localStorage.removeItem('spotfix_email');\r\n localStorage.removeItem('spotfix_session_id');\r\n localStorage.removeItem('spotfix_user_id');\r\n localStorage.setItem('spotfix_widget_is_closed', '1');\r\n}\r\n\n/**\r\n * File uploader handler for managing file attachments with validation and upload capabilities\r\n */\r\nclass FileUploader {\r\n /**\r\n * Create a new FileUploader instance\r\n * @param {function} escapeHtmlHandler - Function to escape HTML strings for security\r\n */\r\n constructor(escapeHtmlHandler) {\r\n /** @type {Array<{id: string, file: File}>} */\r\n this.files = [];\r\n\r\n /** @type {number} Maximum allowed file size in bytes */\r\n this.maxFileSize = 5 * 1024 * 1024; // 5MB\r\n\r\n /** @type {number} Maximum total size for all files in bytes */\r\n this.maxTotalSize = 25 * 1024 * 1024; // 25MB\r\n\r\n /** @type {number} Maximum number of files allowed */\r\n this.maxFiles = 5;\r\n\r\n /** @type {string[]} Allowed MIME types for files */\r\n this.allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'text/plain', 'application/msword'];\r\n\r\n /** @type {function} HTML escaping function for XSS protection */\r\n this.escapeHtmlHandler = escapeHtmlHandler;\r\n\r\n /** @type {string[]} File size units for display */\r\n this.SIZE_UNITS = ['Bytes', 'KB', 'MB', 'GB'];\r\n }\r\n\r\n /**\r\n * Initialize elements and bindings. Should be called only for comments.\r\n * @returns {void}\r\n */\r\n init() {\r\n this.initializeElements();\r\n this.bindFilesInputChange();\r\n }\r\n\r\n /**\r\n * Define widget elements to work with uploader.\r\n * @returns {void}\r\n */\r\n initializeElements() {\r\n /** @type {HTMLInputElement|null} */\r\n this.fileInput = document.getElementById('doboard_task_widget__file-upload__file-input-button');\r\n\r\n /** @type {HTMLElement|null} */\r\n this.fileList = document.getElementById('doboard_task_widget__file-upload__file-list');\r\n\r\n this.uploaderWrapper = document.getElementById('doboard_task_widget__file-upload__wrapper');\r\n\r\n /** @type {HTMLElement|null} */\r\n this.errorMessage = document.getElementById('doboard_task_widget__file-upload__error');\r\n\r\n if (!this.fileInput || !this.fileList || !this.errorMessage || this.uploaderWrapper) {\r\n console.warn('File uploader elements not found');\r\n }\r\n }\r\n\r\n /**\r\n * Define hidden file input change to run uploader logic.\r\n * @returns {void}\r\n */\r\n bindFilesInputChange() {\r\n if (this.fileInput) {\r\n this.fileInput.addEventListener('change', (e) => this.handleFileInputChange(e));\r\n }\r\n }\r\n\r\n /**\r\n * Bind action to paperclip button.\r\n * @param {HTMLElement} element - The paperclip button element\r\n * @returns {void}\r\n */\r\n bindPaperClipAction(element) {\r\n element.addEventListener('click', (e) => {\r\n e.preventDefault();\r\n if (this.fileInput) {\r\n this.fileInput.click();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Handle file input change event\r\n * @param {Event} event - File input change event\r\n * @returns {void}\r\n */\r\n handleFileInputChange(event) {\r\n this.clearError();\r\n\r\n const selectedFiles = Array.from(event.target.files);\r\n if (this.files.length + selectedFiles.length > this.maxFiles) {\r\n this.showError(`Maximum ${this.maxFiles} files can be attached.`);\r\n return;\r\n }\r\n const validFiles = selectedFiles.filter(file => this.validateFile(file));\r\n\r\n validFiles.forEach(file => this.addFile(file));\r\n\r\n // Reset input to allow selecting same files again\r\n event.target.value = '';\r\n\r\n // show wrapper\r\n this.uploaderWrapper.style.display = 'block';\r\n }\r\n\r\n /**\r\n * Validate a file against upload constraints\r\n * @param {File} file - File to validate\r\n * @returns {boolean} True if file is valid, false otherwise\r\n */\r\n validateFile(file) {\r\n // Check file size\r\n if (file.size > this.maxFileSize) {\r\n this.showError(`File \"${file.name}\" is too large. Maximum size: ${this.formatFileSize(this.maxFileSize)}`);\r\n return false;\r\n }\r\n\r\n // Check total size\r\n const totalSize = this.getTotalSize() + file.size;\r\n if (totalSize > this.maxTotalSize) {\r\n this.showError(`Total files size exceeded. Maximum: ${this.formatFileSize(this.maxTotalSize)}`);\r\n return false;\r\n }\r\n\r\n // Check file type\r\n if (this.allowedTypes.length > 0 && !this.allowedTypes.includes(file.type)) {\r\n this.showError(`File type \"${file.type}\" for \"${file.name}\" is not supported.`);\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Calculate total size of all files\r\n * @returns {number} Total size in bytes\r\n */\r\n getTotalSize() {\r\n return this.files.reduce((sum, fileData) => sum + fileData.file.size, 0);\r\n }\r\n\r\n /**\r\n * Add a file to the upload queue\r\n * @param {File} file - File to add\r\n * @returns {void}\r\n */\r\n addFile(file) {\r\n const fileWithId = {\r\n id: this.generateFileId(),\r\n file: file\r\n };\r\n\r\n this.files.push(fileWithId);\r\n this.renderFileList();\r\n }\r\n\r\n /**\r\n * Generate a unique file ID\r\n * @returns {string} Unique file identifier\r\n * @private\r\n */\r\n generateFileId() {\r\n return Date.now() + Math.random().toString(36).substr(2, 9);\r\n }\r\n\r\n /**\r\n * Remove a file from the upload queue\r\n * @param {string} fileId - ID of the file to remove\r\n * @returns {void}\r\n */\r\n removeFile(fileId) {\r\n this.files = this.files.filter(f => f.id !== fileId);\r\n this.renderFileList();\r\n this.clearError();\r\n }\r\n\r\n /**\r\n * Render the file list in the UI\r\n * @returns {void}\r\n */\r\n renderFileList() {\r\n if (!this.fileList) return;\r\n\r\n if (this.files.length === 0) {\r\n this.fileList.innerHTML = ksesFilter('
No files attached
');\r\n return;\r\n }\r\n\r\n const fileItems = this.files.map(fileData => this.createFileItem(fileData));\r\n this.fileList.innerHTML = ksesFilter('');\r\n fileItems.forEach(item => this.fileList.appendChild(item));\r\n }\r\n\r\n /**\r\n * Create file item element for display\r\n * @param {object} fileData - File data object\r\n * @param {string} fileData.id - File identifier\r\n * @param {File} fileData.file - File object\r\n * @returns {HTMLDivElement} File item DOM element\r\n */\r\n createFileItem(fileData) {\r\n const { file, id } = fileData;\r\n const fileItem = document.createElement('div');\r\n fileItem.className = 'doboard_task_widget__file-upload__file-item';\r\n\r\n fileItem.innerHTML = ksesFilter(`\r\n
\r\n
\r\n
${this.escapeHtmlHandler(String(file.name))}
\r\n
${this.formatFileSize(file.size)}
\r\n
\r\n
\r\n \r\n `);\r\n\r\n const removeBtn = fileItem.querySelector('.doboard_task_widget__file-upload__remove-btn');\r\n removeBtn.addEventListener('click', () => this.removeFile(id));\r\n\r\n return fileItem;\r\n }\r\n\r\n /**\r\n * Format file size for display\r\n * @param {number} bytes - File size in bytes\r\n * @returns {string} Formatted file size string\r\n */\r\n formatFileSize(bytes) {\r\n if (bytes === 0) return '0 Bytes';\r\n\r\n const k = 1024;\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n\r\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + this.SIZE_UNITS[i];\r\n }\r\n\r\n /**\r\n * Show uploader error message\r\n * @param {string} message - Error message to display\r\n * @returns {void}\r\n */\r\n showError(message) {\r\n if (this.errorMessage) {\r\n this.errorMessage.textContent = message;\r\n this.errorMessage.style.display = 'block';\r\n }\r\n }\r\n\r\n /**\r\n * Clear uploader error message\r\n * @returns {void}\r\n */\r\n clearError() {\r\n if (this.errorMessage) {\r\n this.errorMessage.textContent = '';\r\n this.errorMessage.style.display = 'none';\r\n }\r\n }\r\n\r\n /**\r\n * Check if there are files to send\r\n * @returns {boolean} True if files are present, false otherwise\r\n */\r\n hasFiles() {\r\n return this.files.length > 0;\r\n }\r\n\r\n /**\r\n * Clear all files from upload queue\r\n * @returns {void}\r\n */\r\n clearFiles() {\r\n this.files = [];\r\n this.renderFileList();\r\n }\r\n\r\n /**\r\n * Validate file data structure before upload\r\n * @param {object} fileData - File data object to validate\r\n * @param {string} fileData.sessionId - Session identifier\r\n * @param {object} fileData.params - Additional parameters\r\n * @param {string} fileData.params.accountId - Account identifier\r\n * @param {string} fileData.params.projectToken - Project token\r\n * @param {string} fileData.commentId - Comment identifier\r\n * @param {string} fileData.fileName - File name\r\n * @param {File} fileData.fileBinary - File binary data\r\n * @returns {object} Validated file data\r\n * @throws {Error} When file data validation fails\r\n */\r\n validateFileData(fileData) {\r\n const validations = [\r\n { field: 'sessionId', type: 'string', message: 'No valid session found.' },\r\n { field: 'params.accountId', type: 'string', message: 'No valid account ID found.' },\r\n { field: 'params.projectToken', type: 'string', message: 'No valid project token found.' },\r\n { field: 'commentId', type: 'string', message: 'No valid commentId found.' },\r\n { field: 'fileName', type: 'string', message: 'No valid filename found.' }\r\n ];\r\n\r\n for (const validation of validations) {\r\n const value = this.getNestedValue(fileData, validation.field);\r\n if (!value || typeof value !== validation.type) {\r\n throw new Error(validation.message);\r\n }\r\n }\r\n\r\n if (!fileData.fileBinary || !(fileData.fileBinary instanceof File)) {\r\n throw new Error('No valid file object found.');\r\n }\r\n\r\n return fileData;\r\n }\r\n\r\n /**\r\n * Helper to get nested object values\r\n * @param {object} obj - Object to traverse\r\n * @param {string} path - Dot notation path to value\r\n * @returns {*} Value at the specified path\r\n * @private\r\n */\r\n getNestedValue(obj, path) {\r\n return path.split('.').reduce((current, key) => current?.[key], obj);\r\n }\r\n\r\n /**\r\n * Send single file attachment\r\n * @param {object} fileData - File data for upload\r\n * @returns {Promise} Upload response\r\n */\r\n async sendSingleAttachment(fileData) {\r\n const validatedFileData = await this.validateFileData(fileData);\r\n return await attachmentAddDoboard(validatedFileData);\r\n }\r\n\r\n /**\r\n * Send all attachments for a comment\r\n * @param {object} params - Upload parameters\r\n * @param {string} sessionId - Session identifier\r\n * @param {string} commentId - Comment identifier\r\n * @returns {Promise} Upload results\r\n */\r\n async sendAttachmentsForComment(params, sessionId, commentId) {\r\n /** @type {object} */\r\n const results = {\r\n preparedFilesCount: this.files.length,\r\n sentFilesCount: 0,\r\n fileResults: [],\r\n success: true\r\n };\r\n\r\n for (let i = 0; i < this.files.length; i++) {\r\n const fileData = this.files[i];\r\n /** @type {object} */\r\n const result = {\r\n success: false,\r\n response: null,\r\n error: null\r\n };\r\n\r\n try {\r\n const attachmentData = {\r\n params,\r\n sessionId,\r\n commentId,\r\n fileName: fileData.file.name,\r\n fileBinary: fileData.file,\r\n attachmentOrder: i\r\n };\r\n\r\n const response = await this.sendSingleAttachment(attachmentData);\r\n result.response = response;\r\n result.success = response.status === 200;\r\n\r\n if (result.success) {\r\n results.sentFilesCount++;\r\n }\r\n } catch (error) {\r\n result.error = error.message;\r\n }\r\n\r\n results.fileResults.push(result);\r\n }\r\n\r\n results.success = results.preparedFilesCount === results.sentFilesCount;\r\n this.clearFiles();\r\n\r\n return results;\r\n }\r\n}\r\n\nclass SpotFixTemplatesLoader {\r\n static getTemplateCode(templateName) {\r\n const templateMethod = this[templateName];\r\n\r\n if (typeof templateMethod !== 'function') {\r\n throw new Error(`Template method '${templateName}' not found`);\r\n }\r\n\r\n let template = templateMethod.call(this).trim();\r\n\r\n return template;\r\n }\r\n\r\n static all_issues() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n All spots \r\n
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n
`;\r\n }\r\n\r\n static concrete_issue() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n All {{issuesCounter}}\r\n
\r\n
{{issueTitle}}
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n \r\n \r\n
\r\n
\r\n
Attached files
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static concrete_issue_day_content() {\r\n return `\r\n
\r\n
{{dayContentMonthDay}}
\r\n
{{dayContentMessages}}
\r\n {{statusFixedHtml}}\r\n
\r\n`;\r\n }\r\n\r\n static concrete_issue_messages() {\r\n return `\r\n
\r\n
\r\n {{taskAuthorInitials}}\r\n
\r\n
\r\n
{{commentBody}}
\r\n
{{commentTime}}
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static create_issue() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n Report an issue\r\n
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n Tell us about any issue you’re experiencing on {{currentDomain}}. \r\n You’re also welcome to review spelling, grammar, or ask a question related to this page.\r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n\r\n If you want to receive notifications by email write here you email contacts.\r\n\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n Note about DoBoard register and accepting email notifications about tasks have to be here.\r\n\r\n
\r\n\r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static list_issues() {\r\n return `\r\n
\r\n
\r\n {{taskAuthorInitials}}\r\n
\r\n
\r\n
\r\n
\r\n {{taskTitle}}\r\n
\r\n \"\"\r\n
\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n {{statusFixedHtml}}\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static user_menu() {\r\n return `\r\n
\r\n
\r\n
\r\n
\r\n \"\"\r\n Back\r\n
\r\n
\r\n \"\"\r\n
\r\n
\r\n
\r\n \"\"\r\n {{userName}}\r\n {{email}}\r\n \r\n Sign up or Log in\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \"\"\r\n
\r\n \r\n \r\n Show widget on my screen\r\n \r\n The widget will be visible again if you select any text on the site\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n \"\"\r\n Log out\r\n \r\n
\r\n
\r\n
\r\n
\r\n {{spotfixVersion}}\r\n Powered by\r\n \r\n doBoard\r\n \r\n
\r\n
\r\n
`;\r\n }\r\n\r\n static wrap() {\r\n return `\r\n
\r\n\r\n\r\n
\r\n
`;\r\n }\r\n\r\n static wrap_review() {\r\n return `\r\n`;\r\n }\r\n\r\n static fixedHtml() {\r\n return `

Finished

`;\r\n }\r\n static fixedTaskHtml() {\r\n return `

This issue already fixed

`;\r\n }\r\n\r\n}\r\n\nclass SpotFixSVGLoader {\r\n static loadSVG(svgName) {\r\n const svgMethod = this[svgName];\r\n\r\n if (typeof svgMethod !== 'function') {\r\n throw new Error(`Template method '${svgName}' not found`);\r\n }\r\n\r\n return svgMethod.call(this).trim();\r\n }\r\n\r\n static getAsRawSVG(svgName) {\r\n return this.loadSVG(svgName);\r\n }\r\n\r\n static getAsDataURI(svgName) {\r\n const svg = this.loadSVG(svgName);\r\n return this.svgToDataURI(svg);\r\n }\r\n\r\n static svgToDataURI(svgString) {\r\n const bytes = new TextEncoder().encode(svgString);\r\n const baseBtoa = btoa(String.fromCharCode(...bytes));\r\n return `data:image/svg+xml;base64,${baseBtoa}`;\r\n }\r\n\r\n static chevronBack() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static chevronBackDark() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static buttonCloseScreen() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static buttonSendMessage() {\r\n return `\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n`;\r\n }\r\n\r\n static buttonPaperClip() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static logoDoBoardGreen() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static logoDoBoardWrap() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotPublic() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotPrivate() {\r\n return `\r\n\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotWidgetWrapPencil() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconLinkChain() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconEllipsesMore() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconAvatar() {\r\n return `\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n`;\r\n }\r\n\r\n static iconEye() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconDoor() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconPlus() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconMaximize() {\r\n return `\r\n\r\n\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconMarker() {\r\n return ``;\r\n }\r\n}\r\n\nclass SpotFixSourcesLoader {\r\n\r\n constructor() {\r\n this.loadAll();\r\n }\r\n\r\n getCSSCode() {\r\n // global gulp wrapper var\r\n return spotFixCSS;\r\n }\r\n\r\n loadAll() {\r\n this.loadFonts();\r\n this.loadCSS();\r\n };\r\n\r\n loadFonts() {\r\n const preconnect_first = document.createElement('link');\r\n preconnect_first.rel = 'preconnect';\r\n preconnect_first.href = 'https://fonts.googleapis.com';\r\n document.head.appendChild(preconnect_first);\r\n\r\n const preconnect_second = document.createElement('link');\r\n preconnect_second.rel = 'preconnect';\r\n preconnect_second.href = 'https://fonts.gstatic.com';\r\n preconnect_second.crossOrigin = 'crossorigin';\r\n document.head.appendChild(preconnect_second);\r\n\r\n const fontLink = document.createElement('link');\r\n fontLink.rel = 'stylesheet';\r\n fontLink.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap';\r\n document.head.appendChild(fontLink);\r\n }\r\n\r\n loadCSS() {\r\n const style = document.createElement('style');\r\n style.setAttribute('id', 'spotfix_css');\r\n style.textContent = this.getCSSCode();\r\n document.head.appendChild(style);\r\n }\r\n}\r\n\ndocument.dispatchEvent(new CustomEvent('spotFixLoaded', {\r\n detail: {\r\n timestamp: new Date().toISOString(),\r\n message: 'All scripts loaded successfully'\r\n }\r\n}));\r\n"],"names":["DOBOARD_API_URL","spotfixApiCall","async","data","method","accountId","undefined","Error","key","formData","FormData","hasOwnProperty","append","let","endpointUrl","URL","error","response","await","fetch","body","networkError","message","responseBody","json","parseError","operation_status","errorMessage","operation_message","userConfirmEmailDoboard","emailConfirmationToken","email_confirmation_token","encodeURIComponent","result","sessionId","session_id","userId","user_id","email","accounts","operationStatus","createTaskDoboard","taskDetails","project_token","projectToken","project_id","projectId","localStorage","getItem","name","taskTitle","comment","taskDescription","meta","taskMeta","task_type","taskId","task_id","createTaskCommentDoboard","status","commentId","comment_id","attachmentAddDoboard","fileData","params","account_id","filename","fileName","file","fileBinary","attachment_order","attachmentOrder","registerUserDoboard","nickname","pageURL","confirmation_url","botDetectorData","JSON","parse","value","bot_detector_event_token","accountExists","user_email_confirmed","operationMessage","userEmailConfirmed","loginUserDoboard","password","logoutUserDoboard","includes","clearLocalstorageOnLogout","getTasksDoboard","tasks","map","task","taskLastUpdate","updated","taskCreated","created","taskCreatorTaskUser","creator_user_id","taskStatus","storageSaveTasksCount","getTasksCommentsDoboard","comments","commentBody","commentDate","issueTitle","task_name","getUserDoboard","users","userUpdateDoboard","timezone","timestamp","success","getReleaseVersion","length","tag_name","storageSaveSpotfixVersion","err","SPOTFIX_VERSION","confirmUserEmail","pendingTaskRaw","setItem","pendingTask","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","removeItem","getTasksFullDetails","currentActiveTaskId","find","item","getUserDetails","currentUserId","sign","window","location","href","addTaskComment","commentText","getUserTasks","getAllTasks","filter","formatDate","dateStr","date","time","dateObj","Date","replace","isNaN","getTime","offsetMinutes","getTimezoneOffset","localDateObj","getMonth","getDate","getHours","toString","padStart","getMinutes","getTaskAuthorDetails","taskAuthorAvatarImgSrc","taskAuthorName","element","getIssuesCounterString","onPageSpotsCount","totalSpotsCount","getAvatarSrc","author","avatar","m","getAuthorName","trim","registerUser","userEmail","userName","then","document","querySelector","innerText","ksesFilter","classList","remove","getElementById","focus","userUpdate","showMessageCallback","catch","loginUser","userPassword","Intl","DateTimeFormat","resolvedOptions","timeZone","spotFixSplitUrl","url","u","domain","segments","reversed","host","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","checkLogInOutButtonsVisible","el","style","display","closest","changeSize","container","add","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","iconPlus","iconMaximize","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardGreen","logoDoBoardWrap","iconSpotWidgetWrapPencil","iconMarker","iconSpotPublic","iconSpotPrivate","iconLinkChain","fileUploader","FileUploader","escapeHtml","getParams","urlParams","URLSearchParams","search","emailToken","get","newUrl","storageSetWidgetIsClosed","delete","history","replaceState","title","registrationShowMessage","isWidgetClosed","taskHasSiteOwnerUpdate","storageTasksHasUnreadUpdates","checkIfTasksHasSiteOwnerUpdates","storageSaveTasksUpdateData","storageWidgetCloseIsSet","createWidgetElement","bindWidgetInputsInteractive","script","src","Object","fromEntries","searchParams","entries","bindCreateTaskEvents","submitButton","taskTitleElement","taskDescriptionElement","loginSectionElement","contains","userEmailElement","userNameElement","userPasswordElement","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","config","SpotfixWidgetConfig","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","position","Number","verticalPosition","version","spotfixVersion","iconEye","iconDoor","chevronBackDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","spotFixScrollToNodePath","spotFixGetSelectedData","nodePath","positionWidgetContainer","getTaskCount","widgetElementClasses","currentTarget","spotFixOpenWidget","issuesQuantityOnPage","spotsToBeHighlighted","currentURL","sortedTasks","sort","a","b","aIsHere","i","elTask","taskMetaString","taskData","isFixed","taskFullDetails","avatarData","currentPageURL","taskNodePath","taskPublicStatusImgSrc","taskPublicStatusHint","getAvatarData","getTaskFullDetails","listIssuesTemplateVariables","taskLastMessage","lastMessageText","taskPageUrl","taskFormattedPageUrl","lastMessageTime","sanitizeNodePath","avatarCSSClass","avatarStyle","taskAuthorInitials","initialsClass","classUnread","elementBgCSSClass","statusFixedHtml","storageProvidedTaskHasUnreadUpdates","isSpotHaveToBeHighlighted","spotFixHighlightElements","bindIssuesClick","user","gitHubAppVersion","s","issueTitleElement","currentTaskData","String","origin","issuesCommentsContainer","protocol","contenerClasess","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","commentUserId","commentAuthorAvatarSrc","commentAuthorName","commentData","commentTime","issueMessageClassOwner","daysWrapperHTML","day","messageId","currentDayMessages","dayMessagesWrapperHTML","localeCompare","currentMessageTemplateVariables","dayContentMonthDay","dayContentMessages","textarea","handleTextareaChange","contentContainer","scrollTo","top","scrollHeight","behavior","sendButton","widgetClass","preventDefault","input","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","spotFixShowWidget","querySelectorAll","forEach","getAttribute","showOneTask","taskHighlightData","getTaskHighlightData","variables","template","SpotFixTemplatesLoader","getTemplateCode","placeholder","replacement","isPlaceholderInAttribute","imgFilter","replaceAll","escapedPlaceholder","RegExp","test","unsafe","tasksCountLS","tasksCount","taskCountElement","wrapElementWithSpotfixHighlight","newElement","cloneNode","wrapper","insertAdjacentElement","taskIdToSearch","currentTaskSpotData","accordionController","context","handleScroll","bind","handleResize","messageText","titleSpan","messageDiv","messageWrap","color","widget","widgetCreateIssue","widgetConcreteIssue","scrollY","viewportHeight","innerHeight","selectionAbsoluteTop","getBoundingClientRect","widgetHeight","offsetHeight","bottom","scrollTimeout","resizeTimeout","str","spotFixShowDelayTimeout","SPOTFIX_DEBUG","SPOTFIX_SHOW_DELAY","spotFixInit","SpotFixSourcesLoader","loadBotDetector","id","head","spotFixIsInsideWidget","node","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","containerClassesToShow","containers","tasksDetails","lastComment","dt","avatarSrc","authorName","authorDetails","charAt","toUpperCase","isAnyTaskUpdated","updatedtasksIDS","currentStateOfTask","issuerId","storageCheckTaskUpdate","updatedTaskIDs","lastMessage","updatedTaskId","updatedTaskData","storageAddUnreadUpdateForTaskID","isSelectionCorrect","html","options","allowedTags","strong","em","ul","ol","li","p","br","span","blockquote","pre","div","img","label","button","details","summary","allowedAttrs","doc","DOMParser","parseFromString","childNodes","clean","tag","tagName","toLowerCase","link","alt","target","parentNode","insertBefore","textContent","attributes","attr","attrName","startsWith","readyState","sel","isWrapReviewWidgetExists","focusNode","anchorNode","spotFixCSS","SPOTFIX_SELECTION_TYPE_TEXT","SPOTFIX_SELECTION_TYPE_IMG","SPOTFIX_SELECTION_TYPE_ELEMENT","spotFixGetSelectionType","range","getRangeAt","commonAncestor","commonAncestorContainer","spotFixGetSelectedImage","startContainer","endContainer","hasTextContent","isTextNode","TEXT_NODE","isCollapsed","collapsed","rangeCount","selectionType","startSelectPosition","endSelectPosition","commonNode","commonNodeElement","startOffset","endOffset","spotFixCalculateNodePath","imgElement","selectedImage","from","children","indexOf","imageUrl","widgetInstance","elementsMap","Map","spot","spotFixIsValidNodePath","spotFixRetrieveNodeFromPath","has","set","spots","spotFixHighlightImageElement","spotFixHighlightNestedElement","spotFixHighlightTextInElement","tooltipTitleText","spotfixHighlightOpen","text","spotSelectedText","markers","startPos","parseInt","endPos","slice","marker","insertText","idClass","cls","path","scrollIntoView","block","spans","affectedParents","Set","elementSelectionClassName","parent","tooltip","firstChild","removeChild","normalize","imageSelectionClassName","every","index","isInteger","imgNode","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","spotFixIsElementInRange","FILTER_ACCEPT","FILTER_REJECT","nextNode","startElement","spotFixGetElementFromNode","endElement","spotFixIsElementPartiallySelected","spotFixFindNearbyElements","elementRange","createRange","selectNode","compareBoundaryPoints","Range","START_TO_START","END_TO_END","elementRect","rangeRect","right","left","elements","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","escapeHtmlHandler","files","maxFileSize","maxTotalSize","maxFiles","allowedTypes","SIZE_UNITS","initializeElements","bindFilesInputChange","fileInput","fileList","uploaderWrapper","warn","handleFileInputChange","click","event","clearError","selectedFiles","validateFile","addFile","size","formatFileSize","getTotalSize","reduce","sum","fileWithId","generateFileId","renderFileList","now","Math","random","substr","removeFile","fileId","f","fileItems","createFileItem","fileItem","bytes","floor","parseFloat","pow","toFixed","clearFiles","validateFileData","validation","field","getNestedValue","File","obj","current","sendSingleAttachment","validatedFileData","results","preparedFilesCount","sentFilesCount","fileResults","attachmentData","templateMethod","call","all_issues","concrete_issue","concrete_issue_day_content","concrete_issue_messages","create_issue","list_issues","user_menu","wrap","wrap_review","fixedHtml","fixedTaskHtml","loadSVG","svgName","svgMethod","getAsRawSVG","svg","svgToDataURI","svgString","TextEncoder","encode","btoa","fromCharCode","iconAvatar","loadAll","getCSSCode","loadFonts","loadCSS","preconnect_first","preconnect_second","rel","fontLink","crossOrigin","setAttribute","dispatchEvent","CustomEvent","detail","toISOString"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"doboard-widget-bundle.min.js","sources":["doboard-widget-bundle.js"],"sourcesContent":["async function deleteDB () {\r\n try {\r\n const dbs = await window.indexedDB.databases();\r\n for (const db of dbs) {\r\n closeAndDeleteDatabase(db.name).catch(() => {});\r\n }\r\n } catch (error) {}\r\n}\r\n\r\nconst closeAndDeleteDatabase = (dbName) => {\r\n return new Promise((resolve, reject) => {\r\n const openReq = indexedDB.open(dbName);\r\n\r\n openReq.onsuccess = () => {\r\n const db = openReq.result;\r\n db.close();\r\n const deleteReq = indexedDB.deleteDatabase(dbName);\r\n deleteReq.onsuccess = () => {\r\n resolve();\r\n };\r\n deleteReq.onerror = (event) => {\r\n reject(event.target.error);\r\n };\r\n };\r\n\r\n openReq.onerror = () => {\r\n const deleteReq = indexedDB.deleteDatabase(dbName);\r\n deleteReq.onsuccess = () => {\r\n resolve();\r\n };\r\n deleteReq.onerror = (event) => {\r\n reject(event.target.error);\r\n };\r\n };\r\n });\r\n};\r\n\r\nfunction putHandler(item, store, e) {\r\n if (item?.user_id || item?.taskId || item?.comment_id) {\r\n const request = store?.put(item);\r\n if (request) {\r\n request.onsuccess = function() {\r\n e.target.result.close();\r\n };\r\n request.onerror = function() {\r\n e.target.result.close();\r\n spotfixIndexedDB.error(request, e);\r\n };\r\n }\r\n }\r\n}\r\n\r\nconst INDEXED_DB_NAME = 'spotfix-localDB';\r\nconst indexedDBVersion = 1;\r\n\r\nconst TABLE_USERS = 'users';\r\nconst TABLE_TASKS = 'tasks';\r\nconst TABLE_COMMENTS = 'comments';\r\n\r\nconst LOCAL_DATA_BASE_TABLE = [\r\n {name: TABLE_USERS, keyPath: 'user_id'},\r\n {name: TABLE_TASKS, keyPath: 'taskId'},\r\n {name: TABLE_COMMENTS, keyPath: 'commentId'},\r\n];\r\n\r\nconst spotfixIndexedDB = {\r\n init: async () => {\r\n return new Promise((resolve, reject) => {\r\n if (!localStorage.getItem('spotfix_session_id')) {\r\n resolve({ needInit: false });\r\n return;\r\n }\r\n\r\n const indexedDBName = spotfixIndexedDB.getIndexedDBName();\r\n const request = window.indexedDB.open(indexedDBName, indexedDBVersion);\r\n\r\n request.onupgradeneeded = (e) => {\r\n const db = e.target.result;\r\n LOCAL_DATA_BASE_TABLE.forEach((item) => {\r\n if (!db.objectStoreNames.contains(item.name)) {\r\n const store = db.createObjectStore(item.name, { keyPath: item.keyPath });\r\n if (item.name === TABLE_COMMENTS) store.createIndex('taskId', 'taskId');\r\n if (item.name === TABLE_TASKS) store.createIndex('userId', 'userId');\r\n }\r\n });\r\n resolve({ needInit: true });\r\n };\r\n\r\n request.onsuccess = (e) => {\r\n const db = e.target.result;\r\n\r\n const missingStores = LOCAL_DATA_BASE_TABLE.filter(item => !db.objectStoreNames.contains(item.name));\r\n if (missingStores.length === 0) {\r\n db.close();\r\n resolve({ needInit: false });\r\n } else {\r\n const newVersion = db.version + 1;\r\n db.close();\r\n const upgradeRequest = window.indexedDB.open(indexedDBName, newVersion);\r\n upgradeRequest.onupgradeneeded = (e2) => {\r\n const db2 = e2.target.result;\r\n missingStores.forEach(item => {\r\n const store = db2.createObjectStore(item.name, { keyPath: item.keyPath });\r\n if (item.name === TABLE_COMMENTS) store.createIndex('taskId', 'taskId');\r\n if (item.name === TABLE_TASKS) store.createIndex('userId', 'userId');\r\n });\r\n };\r\n upgradeRequest.onsuccess = () => resolve({ needInit: true });\r\n upgradeRequest.onerror = (err) => reject(err);\r\n }\r\n };\r\n\r\n request.onerror = (err) => reject(err);\r\n });\r\n },\r\n put: async (table, data) => {\r\n const indexedDBName = spotfixIndexedDB.getIndexedDBName();\r\n const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion);\r\n\r\n indexedDB.onsuccess = function(e) {\r\n let transaction;\r\n try {\r\n transaction = e.target.result.transaction(table, 'readwrite');\r\n } catch (e) {}\r\n const store = transaction?.objectStore(table);\r\n if (Array.isArray(data)) {\r\n data.forEach((item) => {\r\n putHandler(item, store, e);\r\n });\r\n } else {\r\n putHandler(data, store, e);\r\n }\r\n };\r\n },\r\n\r\n delete: async (table, id) => {\r\n const indexedDBName = spotfixIndexedDB.getIndexedDBName();\r\n const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion);\r\n\r\n indexedDB.onsuccess = function(e) {\r\n let transaction;\r\n try {\r\n transaction = e.target.result.transaction(table, 'readwrite');\r\n } catch (e) {}\r\n const store = transaction?.objectStore(table);\r\n store.delete(id);\r\n };\r\n },\r\n\r\n getAll: async (table, indexName, value) => {\r\n const indexedDBName = spotfixIndexedDB.getIndexedDBName();\r\n const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion);\r\n\r\n return await new Promise(\r\n (resolve, reject) => {\r\n indexedDB.onsuccess = function(e) {\r\n let transaction;\r\n try {\r\n transaction = e.target.result.transaction(table, 'readwrite');\r\n } catch (e) {}\r\n const store = transaction?.objectStore(table);\r\n if (store) {\r\n if (indexName && value) {\r\n let index = store.index(indexName);\r\n let request = index.getAll(value);\r\n request.onsuccess = function() {\r\n resolve(request.result);\r\n };\r\n // eslint-disable-next-line prefer-promise-reject-errors\r\n request.onerror = () => reject('Err');\r\n } else {\r\n let request = store.getAll();\r\n request.onsuccess = function() {\r\n resolve(request.result);\r\n };\r\n // eslint-disable-next-line prefer-promise-reject-errors\r\n request.onerror = () => reject('Err');\r\n }\r\n }\r\n };\r\n // eslint-disable-next-line prefer-promise-reject-errors\r\n indexedDB.onerror = () => reject('Err');\r\n },\r\n );\r\n },\r\n\r\n clearPut: async (table, data) => {\r\n await spotfixIndexedDB.clearTable(table, data);\r\n spotfixIndexedDB.put(table, data);\r\n },\r\n\r\n clearTable: async (table) => {\r\n const indexedDBName = spotfixIndexedDB.getIndexedDBName();\r\n const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion);\r\n\r\n indexedDB.onsuccess = function(e) {\r\n let transaction;\r\n try {\r\n transaction = e.target.result.transaction(table, 'readwrite');\r\n } catch (e) {}\r\n const store = transaction?.objectStore(table);\r\n const request = store?.clear();\r\n if (request) {\r\n request.onsuccess = function() {\r\n e.target.result.close();\r\n };\r\n request.onerror = function() {\r\n e.target.result.close();\r\n spotfixIndexedDB.error(request, e);\r\n };\r\n }\r\n };\r\n },\r\n\r\n getTable: async (table) => {\r\n return new Promise((resolve) => {\r\n if (!localStorage.getItem('spotfix_session_id')) {\r\n resolve();\r\n } else {\r\n const indexedDBName = spotfixIndexedDB.getIndexedDBName();\r\n window.indexedDB.open(indexedDBName, indexedDBVersion).onsuccess = function(e) {\r\n let transaction;\r\n try {\r\n transaction = e.target.result.transaction(table);\r\n } catch (e) {\r\n }\r\n const store = transaction?.objectStore(table);\r\n const request = store?.getAll();\r\n if (request) {\r\n request.onsuccess = (event) => {\r\n e.target.result.close();\r\n resolve(event.target.result);\r\n };\r\n request.onerror = function() {\r\n e.target.result.close();\r\n spotfixIndexedDB.error(request, e);\r\n };\r\n }\r\n };\r\n }\r\n });\r\n },\r\n\r\n deleteTable: async (table, index) => {\r\n const indexedDBName = spotfixIndexedDB.getIndexedDBName();\r\n return window.indexedDB.open(indexedDBName, indexedDBVersion).onsuccess = function(e) {\r\n const transaction = e.target.result.transaction(table, 'readwrite');\r\n const store = transaction?.objectStore(table);\r\n const request = store.delete(index);\r\n request.onsuccess = () => {\r\n e.target.result.close();\r\n };\r\n request.onerror = function() {\r\n e.target.result.close();\r\n spotfixIndexedDB.error(request, e);\r\n };\r\n };\r\n },\r\n\r\n getIndexedDBName: () => {\r\n return `${INDEXED_DB_NAME}_${localStorage.getItem('spotfix_session_id')}`;\r\n },\r\n error: (request, error) => {\r\n console.error('IndexedDB', request, error);\r\n },\r\n};\r\n\nconst DOBOARD_API_URL = 'https://api.doboard.com';\r\n\r\n/**\r\n * Makes an API call to the DoBoard endpoint with form data\r\n *\r\n * @param {Object} data - The data to send in the request\r\n * @param {string} method - The API method to call\r\n * @param {string|number} accountId - Optional account ID for the endpoint\r\n *\r\n * @returns {Promise} The response data when operation_status is 'SUCCESS'\r\n */\r\nconst spotfixApiCall = async(data, method, accountId = undefined) => {\r\n if (!data || typeof data !== 'object') {\r\n throw new Error('Data must be a valid object');\r\n }\r\n\r\n if (!method || typeof method !== 'string') {\r\n throw new Error('Method must be a valid string');\r\n }\r\n\r\n if (accountId !== undefined && (typeof accountId !== 'string' && typeof accountId !== 'number')) {\r\n throw new Error('AccountId must be a string or number');\r\n }\r\n\r\n const formData = new FormData();\r\n for (const key in data) {\r\n if (data.hasOwnProperty(key)) {\r\n if (data[key] !== undefined && data[key] !== null) {\r\n formData.append(key, data[key]);\r\n }\r\n }\r\n }\r\n\r\n let endpointUrl;\r\n if (accountId !== undefined) {\r\n endpointUrl = `${DOBOARD_API_URL}/${accountId}/${method}`;\r\n } else {\r\n endpointUrl = `${DOBOARD_API_URL}/${method}`;\r\n }\r\n\r\n try {\r\n new URL(endpointUrl);\r\n } catch (error) {\r\n throw new Error(`Invalid endpoint URL: ${endpointUrl}`);\r\n }\r\n\r\n let response;\r\n try {\r\n response = await fetch(endpointUrl, {\r\n method: 'POST',\r\n body: formData,\r\n });\r\n } catch (networkError) {\r\n throw new Error(`Network error: ${networkError.message}`);\r\n }\r\n\r\n let responseBody;\r\n try {\r\n responseBody = await response.json();\r\n } catch (parseError) {\r\n throw new Error('Failed to parse JSON response from server');\r\n }\r\n\r\n if (!responseBody || typeof responseBody !== 'object') {\r\n throw new Error('Invalid response format from server');\r\n }\r\n\r\n if (!responseBody.data) {\r\n throw new Error('Missing data field in server response');\r\n }\r\n\r\n if (!responseBody.data.operation_status) {\r\n throw new Error('Missing operation_status in response data');\r\n }\r\n\r\n if (responseBody.data.operation_status === 'FAILED') {\r\n const errorMessage = responseBody.data.operation_message || 'Operation failed without specific message';\r\n throw new Error(errorMessage);\r\n }\r\n\r\n if (responseBody.data.operation_status === 'SUCCESS') {\r\n return responseBody.data;\r\n }\r\n\r\n throw new Error(`Unknown operation status: ${responseBody.data.operation_status}`);\r\n}\r\n\r\nconst userConfirmEmailDoboard = async (emailConfirmationToken) => {\r\n const data = {\r\n email_confirmation_token: encodeURIComponent(emailConfirmationToken)\r\n }\r\n const result = await spotfixApiCall(data, 'user_confirm_email');\r\n return {\r\n sessionId: result.session_id,\r\n userId: result.user_id,\r\n email: result.email,\r\n accounts: result.accounts,\r\n operationStatus: result.operation_status\r\n };\r\n};\r\n\r\nconst createTaskDoboard = async (sessionId, taskDetails) => {\r\n const accountId = taskDetails.accountId;\r\n const data = {\r\n session_id: sessionId,\r\n project_token: taskDetails.projectToken,\r\n project_id: taskDetails.projectId,\r\n user_id: localStorage.getItem('spotfix_user_id'),\r\n name: taskDetails.taskTitle,\r\n comment: taskDetails.taskDescription,\r\n meta: taskDetails.taskMeta,\r\n task_type: 'PUBLIC'\r\n }\r\n const result = await spotfixApiCall(data, 'task_add', accountId);\r\n return {\r\n taskId: result.task_id,\r\n }\r\n};\r\n\r\nconst createTaskCommentDoboard = async (accountId, sessionId, taskId, comment, projectToken, status = 'ACTIVE') => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n task_id: taskId,\r\n comment: comment,\r\n status: status\r\n }\r\n const result = await spotfixApiCall(data, 'comment_add', accountId);\r\n return {\r\n commentId: result.comment_id,\r\n };\r\n};\r\n\r\nconst attachmentAddDoboard = async (fileData) => {\r\n const accountId = fileData.params.accountId;\r\n const data = {\r\n session_id: fileData.sessionId,\r\n project_token: fileData.params.projectToken,\r\n account_id: fileData.params.accountId,\r\n comment_id: fileData.commentId,\r\n filename: fileData.fileName,\r\n file: fileData.fileBinary,\r\n attachment_order: fileData.attachmentOrder\r\n }\r\n const result = await spotfixApiCall(data, 'attachment_add', accountId);\r\n // @ToDo need to handle result?\r\n};\r\n\r\nconst registerUserDoboard = async (projectToken, accountId, email, nickname, pageURL) => {\r\n let data = {\r\n project_token: projectToken,\r\n account_id: accountId,\r\n confirmation_url: email,\r\n }\r\n if (email && nickname) {\r\n data.email = email;\r\n data.name = nickname;\r\n }\r\n\r\n if (localStorage.getItem('bot_detector_event_token')) {\r\n try {\r\n const botDetectorData = JSON.parse(localStorage.getItem('bot_detector_event_token'));\r\n if (botDetectorData?.value) {\r\n data.bot_detector_event_token = botDetectorData?.value;\r\n }\r\n } catch (error) {\r\n data.bot_detector_event_token = '';\r\n }\r\n }\r\n const result = await spotfixApiCall(data, 'user_registration');\r\n return {\r\n sessionId: result.session_id,\r\n userId: result.user_id,\r\n email: result.email,\r\n accountExists: result.user_email_confirmed === 1,\r\n operationMessage: result.operation_message,\r\n operationStatus: result.operation_status,\r\n userEmailConfirmed: result.user_email_confirmed,\r\n };\r\n};\r\n\r\nconst loginUserDoboard = async (email, password) => {\r\n const data = {\r\n email: email,\r\n password: password,\r\n }\r\n const result = await spotfixApiCall(data, 'user_authorize');\r\n return {\r\n sessionId: result.session_id,\r\n userId: result.user_id,\r\n email: result.email,\r\n accountExists: result.user_email_confirmed === 1,\r\n operationMessage: result.operation_message,\r\n operationStatus: result.operation_status,\r\n userEmailConfirmed: result.user_email_confirmed,\r\n }\r\n}\r\n\r\nconst logoutUserDoboard = async (projectToken, accountId) => {\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n if(sessionId && accountId) {\r\n const data = {\r\n session_id: sessionId,\r\n };\r\n\r\n const email = localStorage.getItem('spotfix_email') || '';\r\n\r\n if (email && email.includes('spotfix_')) {\r\n data.project_token = projectToken;\r\n }\r\n\r\n const result = await spotfixApiCall(data, 'user_unauthorize', accountId);\r\n\r\n if (result.operation_status === 'SUCCESS') {\r\n await deleteDB();\r\n clearLocalstorageOnLogout();\r\n }\r\n }\r\n}\r\n\r\nconst getTasksDoboard = async (projectToken, sessionId, accountId, projectId, userId) => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n project_id: projectId,\r\n task_type: 'PUBLIC'\r\n }\r\n if ( userId ) {\r\n data.user_id = userId;\r\n }\r\n const result = await spotfixApiCall(data, 'task_get', accountId);\r\n const tasks = result.tasks.map(task => ({\r\n taskId: task.task_id,\r\n taskTitle: task.name,\r\n userId: task.user_id,\r\n taskLastUpdate: task.updated,\r\n taskCreated: task.created,\r\n taskCreatorTaskUser: task.creator_user_id,\r\n taskMeta: task.meta,\r\n taskStatus: task.status,\r\n }));\r\n if (data.task_id) {\r\n await spotfixIndexedDB.put(TABLE_TASKS, tasks);\r\n } else {\r\n await spotfixIndexedDB.clearPut(TABLE_TASKS, tasks);\r\n }\r\n storageSaveTasksCount(tasks);\r\n return tasks;\r\n}\r\n\r\n\r\nconst getTasksCommentsDoboard = async (sessionId, accountId, projectToken, status = 'ACTIVE') => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n status: status\r\n }\r\n const result = await spotfixApiCall(data, 'comment_get', accountId);\r\n const comments = result.comments.map(comment => ({\r\n taskId: comment.task_id,\r\n commentId: comment.comment_id,\r\n userId: comment.user_id,\r\n commentBody: comment.comment,\r\n commentDate: comment.updated,\r\n status: comment.status,\r\n issueTitle: comment.task_name,\r\n }));\r\n if (data.comment_id) {\r\n await spotfixIndexedDB.put(TABLE_COMMENTS, comments);\r\n } else {\r\n await spotfixIndexedDB.clearPut(TABLE_COMMENTS, comments);\r\n }\r\n return comments;\r\n};\r\n\r\nconst getUserDoboard = async (sessionId, projectToken, accountId, userId) => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n }\r\n if (userId) data.user_id = userId;\r\n\r\n const result = await spotfixApiCall(data, 'user_get', accountId);\r\n if (data.user_id) {\r\n await spotfixIndexedDB.put(TABLE_USERS, result.users);\r\n } else {\r\n await spotfixIndexedDB.clearPut(TABLE_USERS, result.users);\r\n }\r\n return result.users;\r\n\r\n // @ToDo Need to handle these two different answers?\r\n /*// Format 1: users inside data\r\n if (responseBody.data && responseBody.data.operation_status) {\r\n if (responseBody.data.operation_status === 'FAILED') {\r\n throw new Error(responseBody.data.operation_message);\r\n }\r\n if (responseBody.data.operation_status === 'SUCCESS') {\r\n if (Array.isArray(responseBody.data.users)) {\r\n return responseBody.data.users;\r\n }\r\n return [];\r\n }\r\n }\r\n // Format 2: users at the top level\r\n if (responseBody.operation_status) {\r\n if (responseBody.operation_status === 'FAILED') {\r\n throw new Error(responseBody.operation_message);\r\n }\r\n if (responseBody.operation_status === 'SUCCESS') {\r\n if (Array.isArray(responseBody.users)) {\r\n return responseBody.users;\r\n }\r\n return [];\r\n }\r\n }*/\r\n};\r\n\r\nconst userUpdateDoboard = async (projectToken, accountId, sessionId, userId, timezone) => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\r\n user_id: userId,\r\n timestamp: timezone\r\n }\r\n await spotfixApiCall(data, 'user_update', accountId);\r\n return {\r\n success: true\r\n };\r\n}\r\n\r\nconst getReleaseVersion = async () => {\r\n try {\r\n const res = await fetch('https://api.github.com/repos/CleanTalk/SpotFix/releases');\r\n const data = await res.json();\r\n\r\n if (data.length > 0 && data[0].tag_name) {\r\n storageSaveSpotfixVersion(data[0].tag_name);\r\n return data[0].tag_name;\r\n }\r\n\r\n return null;\r\n } catch (err) {\r\n return null;\r\n }\r\n};\r\n\r\n\nconst SPOTFIX_VERSION = \"1.1.5\";\r\n\nasync function confirmUserEmail(emailConfirmationToken, params) {\r\n\tconst result = await userConfirmEmailDoboard(emailConfirmationToken);\r\n\t// Save session data to LS\r\n\tlocalStorage.setItem('spotfix_email', result.email);\r\n\tlocalStorage.setItem('spotfix_session_id', result.sessionId);\r\n\tawait spotfixIndexedDB.init();\r\n\tlocalStorage.setItem('spotfix_user_id', result.userId);\r\n\r\n\t// Get pending task from LS\r\n\tconst pendingTaskRaw = localStorage.getItem('spotfix_pending_task');\r\n\tif (!pendingTaskRaw) throw new Error('No pending task data');\r\n\r\n\tlet pendingTask;\r\n\ttry {\r\n\t\tpendingTask = JSON.parse(pendingTaskRaw);\r\n\t} catch (error) {\r\n\t\tthrow new Error('Invalid pending task data');\r\n\t}\r\n\r\n\t// Form taskDetails for task creation\r\n\tconst taskDetails = {\r\n\t\ttaskTitle: pendingTask.selectedText || 'New Task',\r\n\t\ttaskDescription: pendingTask.description || '',\r\n\t\tselectedData: pendingTask,\r\n\t\tprojectToken: params.projectToken,\r\n\t\tprojectId: params.projectId,\r\n\t\taccountId: params.accountId,\r\n\t\ttaskMeta: JSON.stringify(pendingTask)\r\n\t};\r\n\r\n\t// Create task\r\n\tconst createdTask = await handleCreateTask(result.sessionId, taskDetails);\r\n\t// Clear pending task\r\n\tlocalStorage.removeItem('spotfix_pending_task');\r\n\r\n\t// Return created task\r\n\treturn createdTask;\r\n}\r\n\r\nasync function getTasksFullDetails(params, tasks, currentActiveTaskId) {\r\n if (tasks.length > 0) {\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n\t\tawait getTasksCommentsDoboard(sessionId, params.accountId, params.projectToken);\r\n const comments = await spotfixIndexedDB.getAll(TABLE_COMMENTS);\r\n await getUserDoboard(sessionId, params.projectToken, params.accountId);\r\n\t\tconst users = await spotfixIndexedDB.getAll(TABLE_USERS);\r\n\t\tconst foundTask = tasks.find(item => +item.taskId === +currentActiveTaskId);\r\n\r\n return {\r\n comments: comments,\r\n users: users,\r\n\t\t\ttaskStatus: foundTask?.taskStatus,\r\n };\r\n }\r\n}\r\n\r\nasync function getUserDetails(params) {\r\n\t\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\t\tconst currentUserId = localStorage.getItem('spotfix_user_id');\r\n\t\tif(currentUserId) {\r\n\t\t\tawait getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId);\r\n\t\t\tconst users = await spotfixIndexedDB.getAll(TABLE_USERS);\r\n\t\t\treturn users[0] || {};\r\n\t\t}\r\n}\r\n\r\nasync function handleCreateTask(sessionId, taskDetails) {\r\n\ttry {\r\n\t\tconst result = await createTaskDoboard(sessionId, taskDetails);\r\n\t\tif (result && result.taskId && taskDetails.taskDescription) {\r\n const sign = `


The spot has been posted at the following URL ${window.location.href}`;\r\n\t\t\tawait addTaskComment({\r\n\t\t\t\tprojectToken: taskDetails.projectToken,\r\n\t\t\t\taccountId: taskDetails.accountId\r\n\t\t\t}, result.taskId, taskDetails.taskDescription+sign);\r\n\t\t}\r\n\t\treturn result;\r\n\t} catch (err) {\r\n\t\tthrow err;\r\n\t}\r\n}\r\n\r\nasync function addTaskComment(params, taskId, commentText) {\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tif (!sessionId) throw new Error('No session');\r\n\tif (!params.projectToken || !params.accountId) throw new Error('Missing params');\r\n\treturn await createTaskCommentDoboard(params.accountId, sessionId, taskId, commentText, params.projectToken);\r\n}\r\n\r\nasync function getUserTasks(params) {\r\n\tif (!localStorage.getItem('spotfix_session_id')) {\r\n\t\treturn {};\r\n\t}\r\n\tconst projectToken = params.projectToken;\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tconst userId = localStorage.getItem('spotfix_user_id');\r\n\tawait getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId, userId);\r\n\treturn await spotfixIndexedDB.getAll(TABLE_TASKS, 'userId', userId);\r\n}\r\n\r\nasync function getAllTasks(params) {\r\n\tif (!localStorage.getItem('spotfix_session_id')) {\r\n\t\treturn {};\r\n\t}\r\n\tconst projectToken = params.projectToken;\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tawait getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId);\r\n\tconst tasksData = await spotfixIndexedDB.getAll(TABLE_TASKS);\r\n // Get only tasks with metadata\r\n\tconst filteredTaskData = tasksData.filter(task => {\r\n return task.taskMeta;\r\n });\r\n\r\n return filteredTaskData;\r\n}\r\n\r\nfunction formatDate(dateStr) {\r\n\t const months = [\r\n\t \t\"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\r\n\t \t\"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\r\n\t ];\r\n\t // dateStr expected format: 'YYYY-MM-DD HH:mm:ss' or 'YYYY-MM-DDTHH:mm:ssZ'\r\n\t if (!dateStr) return { date: '', time: '' };\r\n\t let dateObj;\r\n\t if (dateStr.includes('T')) {\r\n\t dateObj = new Date(dateStr);\r\n\t } else if (dateStr.includes(' ')) {\r\n\t dateObj = new Date(dateStr.replace(' ', 'T'));\r\n\t } else {\r\n\t dateObj = new Date(dateStr);\r\n\t }\r\n\t if (isNaN(dateObj.getTime())) return { date: '', time: '' };\r\n\r\n\t // Adjust to local timezone\r\n\t const offsetMinutes = dateObj.getTimezoneOffset();\r\n\t let localDateObj = new Date(dateObj.getTime() - offsetMinutes * 60000);\r\n\r\n\t const month = months[localDateObj.getMonth()];\r\n\t const day = localDateObj.getDate();\r\n\t const date = `${month} ${day}`;\r\n\t const hours = localDateObj.getHours().toString().padStart(2, '0');\r\n\t const minutes = localDateObj.getMinutes().toString().padStart(2, '0');\r\n\t const time = `${hours}:${minutes}`;\r\n\t return { date, time };\r\n}\r\n\r\nfunction getTaskAuthorDetails(params, taskId) {\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tconst mockUsersData =\r\n\t\t[\r\n\t\t\t{\r\n\t\t\t\t'taskId': '1',\r\n\t\t\t\t'taskAuthorAvatarImgSrc': 'https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg',\r\n\t\t\t\t'taskAuthorName': 'Test All Issues Single Author Name'\r\n\t\t\t}\r\n\t\t]\r\n\r\n\tconst defaultData =\r\n\t\t{\r\n\t\t\t'taskId': null,\r\n\t\t\t'taskAuthorAvatarImgSrc': null,\r\n\t\t\t'taskAuthorName': 'Task Author'\r\n\t\t};\r\n\r\n\tconst data = mockUsersData.find((element) => element.taskId === taskId);\r\n\treturn data === undefined ? defaultData : data;\r\n}\r\n\r\nfunction getIssuesCounterString(onPageSpotsCount, totalSpotsCount) {\r\n\treturn ` (${onPageSpotsCount}/${totalSpotsCount})`;\r\n}\r\n\r\n// Get the author's avatar\r\nfunction getAvatarSrc(author) {\r\n\tif (author && author.avatar) {\r\n\t\tif (typeof author.avatar === 'object' && author.avatar.m) {\r\n\t\t\treturn author.avatar.m;\r\n\t\t} else if (typeof author.avatar === 'string') {\r\n\t\t\treturn author.avatar;\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n}\r\n\r\n// Get the author's name\r\nfunction getAuthorName(author) {\r\n\tif (author) {\r\n\t\tif (author.name && author.name.trim().length > 0) {\r\n\t\t\treturn author.name;\r\n\t\t} else if (author.email && author.email.trim().length > 0) {\r\n\t\t\treturn author.email;\r\n\t\t}\r\n\t}\r\n\treturn 'Unknown Author';\r\n}\r\n\r\nfunction registerUser(taskDetails) {\r\n\tconst userEmail = taskDetails.userEmail;\r\n\tconst userName = taskDetails.userName;\r\n\tconst projectToken = taskDetails.projectToken;\r\n\tconst accountId = taskDetails.accountId;\r\n\tconst pageURL = taskDetails.selectedData.pageURL ? taskDetails.selectedData.pageURL : window.location.href;\r\n\r\n\tconst resultRegisterUser = (showMessageCallback) => registerUserDoboard(projectToken, accountId, userEmail, userName, pageURL)\r\n\t\t.then(response => {\r\n\t\t\tif (response.accountExists) {\r\n\t\t\t\tdocument.querySelector(\".doboard_task_widget-accordion>.doboard_task_widget-input-container\").innerText = ksesFilter('Account already exists. Please, login usin your password.');\r\n\t\t\t\tdocument.querySelector(\".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden\").classList.remove('hidden');\r\n\t\t\t\tdocument.getElementById(\"doboard_task_widget-user_password\").focus();\r\n\t\t\t} else if (response.sessionId) {\r\n\t\t\t\tlocalStorage.setItem('spotfix_session_id', response.sessionId);\r\n\t\t\t\tspotfixIndexedDB.init();\r\n\t\t\t\tlocalStorage.setItem('spotfix_user_id', response.userId);\r\n\t\t\t\tlocalStorage.setItem('spotfix_email', response.email);\r\n\t\t\t\tuserUpdate(projectToken, accountId);\r\n\t\t\t} else if (response.operationStatus === 'SUCCESS' && response.operationMessage && response.operationMessage.length > 0) {\r\n\t\t\t\tif (response.operationMessage == 'Waiting for email confirmation') {\r\n\t\t\t\t\tresponse.operationMessage = 'Waiting for an email confirmation. Please check your Inbox.';\r\n\t\t\t\t}\r\n\t\t\t\tif (typeof showMessageCallback === 'function') {\r\n\t\t\t\t\tshowMessageCallback(response.operationMessage, 'notice');\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tthrow new Error('Session ID not found in response');\r\n\t\t\t}\r\n\t\t})\r\n\t\t.catch(error => {\r\n\t\t\tthrow error;\r\n\t\t});\r\n\r\n\t\treturn resultRegisterUser;\r\n}\r\n\r\nfunction loginUser(taskDetails) {\r\n\tconst userEmail = taskDetails.userEmail;\r\n\tconst userPassword = taskDetails.userPassword;\r\n\r\n\treturn (showMessageCallback) => loginUserDoboard(userEmail, userPassword)\r\n\t\t.then(response => {\r\n\t\t\tif (response.sessionId) {\r\n\t\t\t\tlocalStorage.setItem('spotfix_session_id', response.sessionId);\r\n\t\t\t\tspotfixIndexedDB.init();\r\n\t\t\t\tlocalStorage.setItem('spotfix_user_id', response.userId);\r\n\t\t\t\tlocalStorage.setItem('spotfix_email', userEmail);\r\n\t\t\t} else if (response.operationStatus === 'SUCCESS' && response.operationMessage && response.operationMessage.length > 0) {\r\n\t\t\t\tif (typeof showMessageCallback === 'function') {\r\n\t\t\t\t\tshowMessageCallback(response.operationMessage, 'notice');\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tthrow new Error('Session ID not found in response');\r\n\t\t\t}\r\n\t\t})\r\n\t\t.catch(error => {\r\n\t\t\tthrow error;\r\n\t\t});\r\n}\r\n\r\nfunction userUpdate(projectToken, accountId) {\r\n\tconst sessionId = localStorage.getItem('spotfix_session_id');\r\n\tconst userId = localStorage.getItem('spotfix_user_id');\r\n\tconst timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\r\n\r\n\treturn userUpdateDoboard(projectToken, accountId, sessionId, userId, timezone);\r\n}\r\n\r\nfunction spotFixSplitUrl(url) {\r\n\ttry {\r\n\t\tif (!url || url.trim() === '') {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\tconst u = new URL(url);\r\n\t\tconst domain = u.host;\r\n\r\n\t\tconst segments = u.pathname.split('/').filter(Boolean);\r\n\r\n\t\tif (segments.length === 0) {\r\n\t\t\treturn domain;\r\n\t\t}\r\n\r\n\t\tconst reversed = segments.reverse();\r\n\t\treversed.push(domain);\r\n\t\treturn reversed.join(' / ');\r\n\t} catch (error) {\r\n\t\treturn '';\r\n\t}\r\n\r\n}\r\n\r\nfunction setToggleStatus(rootElement){\r\n\tconst clickHandler = () => {\r\n\t\tconst timer = setTimeout(() => {\r\n\t\t\tlocalStorage.setItem('spotfix_widget_is_closed', '1');\r\n\t\t\trootElement.hide();\r\n\t\t\tclearTimeout(timer);\r\n\t\t}, 300);\r\n\t};\r\n\tconst toggle = document.getElementById('widget_visibility');\r\n\tif(toggle) {\r\n\t\ttoggle.checked = true;\r\n\t\ttoggle.addEventListener('click', clickHandler);\r\n\t}\r\n}\r\n\r\nfunction checkLogInOutButtonsVisible (){\r\n\tif(!localStorage.getItem('spotfix_session_id')) {\r\n\t\tconst el = document\r\n\t\t\t.getElementById('doboard_task_widget-user_menu-logout_button')\r\n\t\t\t?.closest('.doboard_task_widget-user_menu-item');\r\n\t\t\tif(el) el.style.display = 'none';\r\n\t} else {\r\n\t\tconst el = document.getElementById('doboard_task_widget-user_menu-signlog_button');\r\n\t\tif(el) el.style.display = 'none';\r\n\t}\r\n}\r\n\r\nfunction changeSize(container){\r\n\tif(container && +localStorage.getItem('maximize')){\r\n\t\tcontainer.classList.add('doboard_task_widget-container-maximize');\r\n\t} else if(container) {\r\n\t\tcontainer.classList.remove('doboard_task_widget-container-maximize');\r\n\t}\r\n}\r\n\n/**\r\n * Widget class to create a task widget\r\n */\r\nclass CleanTalkWidgetDoboard {\r\n selectedText = '';\r\n selectedData = {};\r\n widgetElement = null;\r\n params = {};\r\n currentActiveTaskId = 0;\r\n savedIssuesQuantityOnPage = 0;\r\n savedIssuesQuantityAll = 0;\r\n allTasksData = {};\r\n srcVariables = {};\r\n\r\n /**\r\n * Constructor\r\n */\r\n constructor(selectedData, type) {\r\n this.selectedData = selectedData || '';\r\n this.selectedText = selectedData?.selectedText || '';\r\n this.init(type);\r\n this.srcVariables = {\r\n buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'),\r\n iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'),\r\n iconPlus: SpotFixSVGLoader.getAsDataURI('iconPlus'),\r\n iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'),\r\n chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardGreen: SpotFixSVGLoader.getAsDataURI('logoDoBoardGreen'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\r\n iconMarker: SpotFixSVGLoader.getAsDataURI('iconMarker'),\r\n iconSpotPublic: SpotFixSVGLoader.getAsDataURI('iconSpotPublic'),\r\n iconSpotPrivate: SpotFixSVGLoader.getAsDataURI('iconSpotPrivate'),\r\n iconLinkChain: SpotFixSVGLoader.getAsDataURI('iconLinkChain'),\r\n };\r\n this.fileUploader = new FileUploader(this.escapeHtml);\r\n }\r\n\r\n /**\r\n * Initialize the widget\r\n */\r\n async init(type) {\r\n this.params = this.getParams();\r\n\r\n // Check if email_confirmation_token is in URL\r\n const urlParams = new URLSearchParams(window.location.search);\r\n const emailToken = urlParams.get('email_confirmation_token');\r\n if (emailToken) {\r\n try {\r\n // Confirm email and create task\r\n const createdTask = await confirmUserEmail(emailToken, this.params);\r\n this.allTasksData = await getAllTasks(this.params);\r\n // Open task interface\r\n this.currentActiveTaskId = createdTask.taskId;\r\n type = 'concrete_issue';\r\n storageSetWidgetIsClosed(false);\r\n // Clear email_confirmation_token from URL\r\n urlParams.delete('email_confirmation_token');\r\n const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '');\r\n window.history.replaceState({}, document.title, newUrl);\r\n } catch (err) {\r\n this.registrationShowMessage('Error confirming email: ' + err.message, 'error');\r\n }\r\n } else {\r\n // Load all tasks\r\n const isWidgetClosed = localStorage.getItem('spotfix_widget_is_closed');\r\n if((isWidgetClosed && !this.selectedText) || !isWidgetClosed){\r\n this.allTasksData = await getAllTasks(this.params);\r\n }\r\n }\r\n\r\n // Check if any task has updates\r\n let taskHasSiteOwnerUpdate;\r\n\r\n if (storageTasksHasUnreadUpdates()) {\r\n taskHasSiteOwnerUpdate = true;\r\n } else {\r\n if (type === 'wrap_review') {\r\n taskHasSiteOwnerUpdate = await checkIfTasksHasSiteOwnerUpdates(\r\n this.allTasksData,\r\n this.params\r\n );\r\n }\r\n }\r\n storageSaveTasksUpdateData(this.allTasksData);\r\n //check to hide on first run\r\n if (!storageWidgetCloseIsSet()) {\r\n storageSetWidgetIsClosed(true);\r\n }\r\n //check to show if any task has site owner updates\r\n if (taskHasSiteOwnerUpdate) {\r\n\r\n storageSetWidgetIsClosed(false);\r\n }\r\n this.widgetElement = await this.createWidgetElement(type);\r\n this.bindWidgetInputsInteractive();\r\n }\r\n\r\n getParams() {\r\n const script = document.querySelector(`script[src*=\"doboard-widget-bundle.\"]`);\r\n if ( ! script || ! script.src ) {\r\n throw new Error('Script not provided');\r\n }\r\n\r\n const url = new URL(script.src);\r\n let params = Object.fromEntries(url.searchParams.entries());\r\n if ( ! params ) {\r\n throw new Error('Script params not provided');\r\n }\r\n if ( ! params.projectToken || ! params.accountId || ! params.projectId ) {\r\n throw new Error('Necessary script params not provided');\r\n\r\n }\r\n return params;\r\n }\r\n\r\n /**\r\n * Binding events to create a task\r\n */\r\n bindCreateTaskEvents() {\r\n const submitButton = document.getElementById('doboard_task_widget-submit_button');\r\n\r\n if (submitButton) {\r\n submitButton.addEventListener('click', async () => {\r\n // Check required fields: Report about and Description\r\n const taskTitleElement = document.getElementById('doboard_task_widget-title');\r\n const taskTitle = taskTitleElement.value;\r\n if ( ! taskTitle ) {\r\n taskTitleElement.style.borderColor = 'red';\r\n taskTitleElement.focus();\r\n taskTitleElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n const taskDescriptionElement = document.getElementById('doboard_task_widget-description')\r\n const taskDescription = taskDescriptionElement.value;\r\n if ( ! taskDescription ) {\r\n taskDescriptionElement.style.borderColor = 'red';\r\n taskDescriptionElement.focus();\r\n taskDescriptionElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n\r\n // If login section is open, check required fields: Nickname, Email\r\n let userName = '';\r\n let userEmail = '';\r\n let userPassword = '';\r\n const loginSectionElement = document.querySelector('.doboard_task_widget-login');\r\n\r\n if ( loginSectionElement && loginSectionElement.classList.contains('active') ) {\r\n const userEmailElement = document.getElementById('doboard_task_widget-user_email');\r\n const userNameElement = document.getElementById('doboard_task_widget-user_name');\r\n const userPasswordElement = document.getElementById('doboard_task_widget-user_password');\r\n\r\n userEmail = userEmailElement.value;\r\n if ( ! userEmail ) {\r\n userEmailElement.style.borderColor = 'red';\r\n userEmailElement.focus();\r\n userEmailElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n\r\n // This is the registration request\r\n if ( userEmailElement && userNameElement ) {\r\n userName = userNameElement.value;\r\n if ( ! userName ) {\r\n userNameElement.style.borderColor = 'red';\r\n userNameElement.focus();\r\n userNameElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n }\r\n\r\n // This is the login request\r\n if ( userEmailElement && userPasswordElement && ! userNameElement ) {\r\n userPassword = userPasswordElement.value;\r\n if ( ! userPassword ) {\r\n userPasswordElement.style.borderColor = 'red';\r\n userPasswordElement.focus();\r\n userPasswordElement.addEventListener('input', function() {\r\n this.style.borderColor = '';\r\n });\r\n return;\r\n }\r\n }\r\n\r\n }\r\n\r\n // If it is the login request\r\n const userEmailElement = document.getElementById('doboard_task_widget-user_email');\r\n userEmail = userEmailElement.value;\r\n\r\n // Make the submit button disable with spinner\r\n const submitButton = document.getElementById('doboard_task_widget-submit_button');\r\n submitButton.disabled = true;\r\n submitButton.innerText = ksesFilter('Creating spot...');\r\n\r\n let taskDetails = {\r\n taskTitle: taskTitle,\r\n taskDescription: taskDescription,\r\n //typeSend: typeSend,\r\n selectedData: this.selectedData,\r\n projectToken: this.params.projectToken,\r\n projectId: this.params.projectId,\r\n accountId: this.params.accountId,\r\n taskMeta: JSON.stringify(this.selectedData ? this.selectedData : { pageURL: window.location.href }),\r\n };\r\n\r\n if ( userEmail ) {\r\n taskDetails.userEmail = userEmail\r\n }\r\n if ( userName ) {\r\n taskDetails.userName = userName\r\n }\r\n if ( userPassword ) {\r\n taskDetails.userPassword = userPassword\r\n }\r\n\r\n // Save pending task in LS\r\n localStorage.setItem('spotfix_pending_task', JSON.stringify({\r\n ...this.selectedData,\r\n description: taskDescription\r\n }));\r\n\r\n let submitTaskResult;\r\n try {\r\n submitTaskResult = await this.submitTask(taskDetails);\r\n } catch (error) {\r\n this.registrationShowMessage(error.message);\r\n return;\r\n }\r\n\r\n // Return the submit button normal state\r\n submitButton.disabled = false;\r\n submitButton.style.cursor = 'pointer';\r\n\r\n if ( submitTaskResult.needToLogin ) {\r\n // @ToDo Do not know what to de here: throw an error or pass log message?\r\n return;\r\n }\r\n\r\n if ( submitTaskResult.isPublic !== undefined ) {\r\n this.selectedData.isPublic = submitTaskResult.isPublic\r\n }\r\n\r\n // refersh tasks list after creation\r\n this.allTasksData = await getAllTasks(this.params);\r\n // save updates\r\n storageSaveTasksUpdateData(this.allTasksData);\r\n\r\n this.selectedData = {};\r\n await this.createWidgetElement('all_issues');\r\n storageSetWidgetIsClosed(false);\r\n hideContainersSpinner(false);\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Create widget element\r\n * @return {HTMLElement} widget element\r\n */\r\n async createWidgetElement(type, showOnlyCurrentPage = false) {\r\n const widgetContainer = document.querySelector('.doboard_task_widget') ? document.querySelector('.doboard_task_widget') : document.createElement('div');\r\n widgetContainer.className = 'doboard_task_widget';\r\n widgetContainer.innerHTML = ksesFilter('');\r\n widgetContainer.removeAttribute('style');\r\n\r\n let templateName = '';\r\n let tasksFullDetails;\r\n\r\n let templateVariables = {};\r\n\r\n const config = window.SpotfixWidgetConfig;\r\n\r\n switch (type) {\r\n case 'create_issue':\r\n templateName = 'create_issue';\r\n this.type_name = templateName;\r\n templateVariables = {\r\n selectedText: this.selectedText,\r\n currentDomain: document.location.hostname || '',\r\n buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'),\r\n iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'),\r\n iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'),\r\n ...this.srcVariables\r\n };\r\n storageGetUserIsDefined() && storageSetWidgetIsClosed(false);\r\n break;\r\n case 'wrap':\r\n if (storageGetWidgetIsClosed()) {\r\n return;\r\n }\r\n\r\n templateName = 'wrap';\r\n templateVariables = {position: !Number.isNaN(Number(config?.verticalPosition))\r\n ? `${Number(config?.verticalPosition)}vh` : '0vh', ...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {position: !Number.isNaN(Number(config?.verticalPosition))\r\n ? `${Number(config?.verticalPosition)}vh` : '0vh', ...this.srcVariables};\r\n break;\r\n case 'all_issues':\r\n templateName = 'all_issues';\r\n this.type_name = templateName;\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'user_menu':\r\n templateName = 'user_menu';\r\n const version = localStorage.getItem('spotfix_app_version') || SPOTFIX_VERSION;\r\n templateVariables = {\r\n spotfixVersion: version ? 'Spotfix version ' + version + '.' : '',\r\n avatar: SpotFixSVGLoader.getAsDataURI('iconAvatar'),\r\n iconEye: SpotFixSVGLoader.getAsDataURI('iconEye'),\r\n iconDoor: SpotFixSVGLoader.getAsDataURI('iconDoor'),\r\n chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'),\r\n buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'),\r\n userName: 'Guest',\r\n email: localStorage.getItem('spotfix_email') || '',\r\n ...this.srcVariables};\r\n break;\r\n case 'concrete_issue':\r\n templateName = 'concrete_issue';\r\n this.type_name = templateName;\r\n // Update the number of tasks\r\n this.savedIssuesQuantityAll = Array.isArray(this.allTasksData) ? this.allTasksData.length : 0;\r\n // Calculate the number of issues on the current page\r\n this.savedIssuesQuantityOnPage = Array.isArray(this.allTasksData)\r\n ? this.allTasksData.filter(task => {\r\n try {\r\n const meta = task.taskMeta ? JSON.parse(task.taskMeta) : {};\r\n return meta.pageURL === window.location.href;\r\n } catch (e) { return false; }\r\n }).length\r\n : 0;\r\n\r\n templateVariables = {\r\n issueTitle: '...',\r\n issueComments: [],\r\n issuesCounter: getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll),\r\n ...this.srcVariables,\r\n };\r\n break;\r\n default:\r\n break;\r\n }\r\n widgetContainer.innerHTML = this.loadTemplate(templateName, templateVariables);\r\n document.body.appendChild(widgetContainer);\r\n\r\n // remove highlights before any screen called\r\n spotFixRemoveHighlights();\r\n const container = document.querySelector('.doboard_task_widget-container');\r\n switch (type) {\r\n case 'create_issue':\r\n\r\n if(container && +localStorage.getItem('maximize')){\r\n container.classList.add('doboard_task_widget-container-maximize');\r\n } else if(container) {\r\n container.classList.remove('doboard_task_widget-container-maximize');\r\n }\r\n // highlight selected item during task creation\r\n const selection = window.getSelection();\r\n const sessionIdExists = !!localStorage.getItem('spotfix_session_id');\r\n const email = localStorage.getItem('spotfix_email');\r\n\r\n if (sessionIdExists && email && !email.includes('spotfix_')) {\r\n document.querySelector('.doboard_task_widget-login').classList.add('hidden');\r\n }\r\n if (\r\n selection.type === 'Range'\r\n ) {\r\n const selectedData = spotFixGetSelectedData(selection);\r\n spotFixScrollToNodePath(selectedData.nodePath);\r\n this.positionWidgetContainer();\r\n }\r\n // bind creation events\r\n this.bindCreateTaskEvents();\r\n break;\r\n case 'wrap':\r\n await this.getTaskCount();\r\n document.querySelector('.doboard_task_widget-wrap').addEventListener('click', (e) => {\r\n const widgetElementClasses = e.currentTarget.classList;\r\n if (widgetElementClasses && !widgetElementClasses.contains('hidden')) {\r\n this.createWidgetElement('all_issues');\r\n }\r\n });\r\n hideContainersSpinner(false);\r\n break;\r\n case 'wrap_review':\r\n document.querySelector('#doboard_task_widget_button').addEventListener('click', (e) => {\r\n spotFixOpenWidget(this.selectedData, 'create_issue');\r\n });\r\n break;\r\n case 'all_issues':\r\n changeSize(container);\r\n\r\n spotFixRemoveHighlights();\r\n let issuesQuantityOnPage = 0;\r\n if (!this.allTasksData?.length) {\r\n this.allTasksData = await getAllTasks(this.params);\r\n }\r\n const tasks = this.allTasksData;\r\n tasksFullDetails = await getTasksFullDetails(this.params, tasks, this.currentActiveTaskId);\r\n let spotsToBeHighlighted = [];\r\n if (tasks.length > 0) {\r\n const currentURL = window.location.href;\r\n const sortedTasks = tasks.sort((a, b) => {\r\n const aIsHere = JSON.parse(a.taskMeta).pageURL === currentURL ? 1 : 0;\r\n const bIsHere = JSON.parse(b.taskMeta).pageURL === currentURL ? 1 : 0;\r\n return bIsHere - aIsHere;\r\n });\r\n\r\n document.querySelector(\".doboard_task_widget-all_issues-container\").innerHTML = '';\r\n\r\n for (let i = 0; i < sortedTasks.length; i++) {\r\n const elTask = sortedTasks[i];\r\n\r\n // Data from api\r\n const taskId = elTask.taskId;\r\n const taskTitle = elTask.taskTitle;\r\n const taskMetaString = elTask.taskMeta;\r\n let taskData = null;\r\n if (taskMetaString) {\r\n try {\r\n taskData = JSON.parse(taskMetaString);\r\n taskData.isFixed = elTask.taskStatus === 'DONE';\r\n taskData.taskId = elTask.taskId;\r\n } catch (error) {\r\n taskData = null;\r\n }\r\n }\r\n const currentPageURL = taskData ? taskData.pageURL : '';\r\n const taskNodePath = taskData ? taskData.nodePath : '';\r\n\r\n // Define publicity details\r\n let taskPublicStatusImgSrc = '';\r\n let taskPublicStatusHint = 'Task publicity is unknown'\r\n if (taskData && taskData.isPublic !== undefined) {\r\n if (taskData.isPublic) {\r\n taskPublicStatusImgSrc = this.srcVariables.iconSpotPublic;\r\n taskPublicStatusHint = 'The task is public';\r\n } else {\r\n taskPublicStatusImgSrc = this.srcVariables.iconSpotPrivate;\r\n taskPublicStatusHint = 'The task is private and visible only for registered DoBoard users';\r\n }\r\n }\r\n\r\n if(currentPageURL === window.location.href){\r\n issuesQuantityOnPage++;\r\n }\r\n\r\n if (!showOnlyCurrentPage || currentPageURL === window.location.href) {\r\n\r\n const taskFullDetails = getTaskFullDetails(tasksFullDetails, taskId)\r\n\r\n const avatarData = getAvatarData(taskFullDetails);\r\n const listIssuesTemplateVariables = {\r\n taskTitle: taskTitle || '',\r\n taskAuthorAvatarImgSrc: taskFullDetails.taskAuthorAvatarImgSrc,\r\n taskAuthorName: taskFullDetails.taskAuthorName,\r\n taskPublicStatusImgSrc: taskPublicStatusImgSrc,\r\n taskPublicStatusHint: taskPublicStatusHint,\r\n taskLastMessage: ksesFilter(taskFullDetails.lastMessageText),\r\n taskPageUrl: currentPageURL,\r\n iconLinkChain: this.srcVariables.iconLinkChain,\r\n taskFormattedPageUrl: spotFixSplitUrl(currentPageURL),\r\n taskLastUpdate: taskFullDetails.lastMessageTime,\r\n nodePath: this.sanitizeNodePath(taskNodePath),\r\n taskId: taskId,\r\n avatarCSSClass: avatarData.avatarCSSClass,\r\n avatarStyle: avatarData.avatarStyle,\r\n taskAuthorInitials: avatarData.taskAuthorInitials,\r\n initialsClass: avatarData.initialsClass,\r\n classUnread: '',\r\n elementBgCSSClass: elTask.taskStatus !== 'DONE' ? '' : 'doboard_task_widget-task_row-green',\r\n statusFixedHtml: elTask.taskStatus !== 'DONE' ? '' : this.loadTemplate('fixedHtml'),\r\n };\r\n\r\n const taskOwnerReplyIsUnread = storageProvidedTaskHasUnreadUpdates(taskFullDetails.taskId);\r\n if (taskOwnerReplyIsUnread) {\r\n listIssuesTemplateVariables.classUnread = 'unread';\r\n }\r\n document.querySelector(\".doboard_task_widget-all_issues-container\").innerHTML += this.loadTemplate('list_issues', listIssuesTemplateVariables);\r\n\r\n if ( this.isSpotHaveToBeHighlighted(taskData) ) {\r\n spotsToBeHighlighted.push(taskData);\r\n }\r\n }\r\n }\r\n this.savedIssuesQuantityOnPage = issuesQuantityOnPage;\r\n this.savedIssuesQuantityAll = tasks.length;\r\n spotFixHighlightElements(spotsToBeHighlighted, this);\r\n document.querySelector('.doboard_task_widget-header span').innerHTML += ksesFilter(' ' + getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll));\r\n }\r\n\r\n if (tasks.length === 0) {\r\n document.querySelector(\".doboard_task_widget-all_issues-container\").innerHTML = ksesFilter('
The issues list is empty
');\r\n }\r\n\r\n // Bind the click event to the task elements for scrolling to the selected text and Go to concrete issue interface by click issue-item row\r\n this.bindIssuesClick();\r\n hideContainersSpinner(false);\r\n break;\r\n case 'user_menu':\r\n\r\n setToggleStatus(this);\r\n checkLogInOutButtonsVisible();\r\n\r\n const user = await getUserDetails(this.params);\r\n const gitHubAppVersion = await getReleaseVersion();\r\n let spotfixVersion = '';\r\n const version = localStorage.getItem('spotfix_app_version') || gitHubAppVersion || SPOTFIX_VERSION;\r\n spotfixVersion = version ? `Spotfix version ${version}.` : '';\r\n\r\n templateVariables.spotfixVersion = spotfixVersion || '';\r\n\r\n if(user){\r\n templateVariables.userName = user.name || 'Guest';\r\n templateVariables.email = user.email || localStorage.getItem('spotfix_email') || '';\r\n if(user?.avatar?.s) templateVariables.avatar = user?.avatar?.s;\r\n }\r\n\r\n widgetContainer.innerHTML = this.loadTemplate('user_menu', templateVariables);\r\n document.body.appendChild(widgetContainer);\r\n setToggleStatus(this);\r\n checkLogInOutButtonsVisible();\r\n\r\n break;\r\n case 'concrete_issue':\r\n changeSize(container);\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n // Update issue title in the interface\r\n const issueTitleElement = document.querySelector('.doboard_task_widget-issue-title');\r\n if (issueTitleElement) {\r\n issueTitleElement.innerText = ksesFilter(taskDetails.issueTitle);\r\n }\r\n\r\n templateVariables.issueTitle = taskDetails?.issueTitle;\r\n templateVariables.issueComments = taskDetails?.issueComments;\r\n\r\n\r\n // Highlight the task's selected text\r\n let nodePath = null;\r\n const currentTaskData = this.allTasksData.find((element) => String(element.taskId) === String(taskDetails.taskId));\r\n let meta = null;\r\n\r\n if (currentTaskData && currentTaskData.taskMeta) {\r\n try {\r\n meta = JSON.parse(currentTaskData.taskMeta);\r\n nodePath = meta.nodePath || null;\r\n } catch (e) { nodePath = null; meta = null; }\r\n }\r\n\r\n templateVariables.taskPageUrl = meta.pageURL;\r\n const taskFormattedPageUrl = meta.pageURL.replace(window.location.origin, '');\r\n templateVariables.taskFormattedPageUrl = taskFormattedPageUrl.length < 2\r\n ? meta.pageURL.replace(window.location.protocol + '/', '') : taskFormattedPageUrl;\r\n templateVariables.contenerClasess = +localStorage.getItem('maximize')\r\n ? 'doboard_task_widget-container-maximize doboard_task_widget-container' : 'doboard_task_widget-container'\r\n widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\r\n\r\n // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\r\n\r\n if (meta && nodePath) {\r\n // Pass the task meta object as an array\r\n spotFixHighlightElements([meta], this);\r\n if (typeof spotFixScrollToNodePath === 'function') {\r\n spotFixScrollToNodePath(nodePath);\r\n }\r\n }\r\n\r\n const issuesCommentsContainer = document.querySelector('.doboard_task_widget-concrete_issues-container');\r\n let dayMessagesData = [];\r\n const initIssuerID = localStorage.getItem('spotfix_user_id');\r\n let userIsIssuer = false;\r\n if ( taskDetails.issueComments.length > 0 ) {\r\n storageRemoveUnreadUpdateForTaskID(taskDetails.taskId);\r\n issuesCommentsContainer.innerHTML = ksesFilter('');\r\n for (const comment of taskDetails.issueComments) {\r\n userIsIssuer = Number(initIssuerID) === Number(comment.commentUserId);\r\n const avatarData = getAvatarData({\r\n taskAuthorAvatarImgSrc: comment.commentAuthorAvatarSrc,\r\n taskAuthorName: comment.commentAuthorName,\r\n });\r\n const commentData = {\r\n commentAuthorName: comment.commentAuthorName,\r\n commentBody: comment.commentBody,\r\n commentDate: comment.commentDate,\r\n commentTime: comment.commentTime,\r\n issueTitle: templateVariables.issueTitle,\r\n avatarCSSClass: avatarData.avatarCSSClass,\r\n avatarStyle: avatarData.avatarStyle,\r\n taskAuthorInitials: avatarData.taskAuthorInitials,\r\n initialsClass: avatarData.initialsClass,\r\n issueMessageClassOwner: userIsIssuer ? 'owner' : 'guest',\r\n };\r\n if (dayMessagesData[comment.commentDate] === undefined) {\r\n dayMessagesData[comment.commentDate] = [];\r\n dayMessagesData[comment.commentDate].push(commentData);\r\n } else {\r\n dayMessagesData[comment.commentDate].push(commentData);\r\n }\r\n }\r\n let daysWrapperHTML = '';\r\n\r\n for (const day in dayMessagesData) {\r\n let currentDayMessages = dayMessagesData[day];\r\n let dayMessagesWrapperHTML = '';\r\n currentDayMessages.sort((a, b) => a.commentTime.localeCompare(b.commentTime));\r\n for (const messageId in currentDayMessages) {\r\n let currentMessageTemplateVariables = currentDayMessages[messageId];\r\n dayMessagesWrapperHTML += this.loadTemplate('concrete_issue_messages', currentMessageTemplateVariables);\r\n }\r\n daysWrapperHTML += this.loadTemplate('concrete_issue_day_content',\r\n {\r\n dayContentMonthDay: day,\r\n dayContentMessages: dayMessagesWrapperHTML,\r\n statusFixedHtml: tasksFullDetails?.taskStatus !== 'DONE' ? '' : this.loadTemplate('fixedTaskHtml')\r\n },\r\n );\r\n }\r\n issuesCommentsContainer.innerHTML = daysWrapperHTML;\r\n } else {\r\n issuesCommentsContainer.innerHTML = ksesFilter('No comments');\r\n }\r\n\r\n // textarea (new comment) behaviour\r\n const textarea = document.querySelector('.doboard_task_widget-send_message_input');\r\n if (textarea) {\r\n function handleTextareaChange() {\r\n const triggerChars = 40;\r\n\r\n if (this.value.length > triggerChars) {\r\n this.classList.add('high');\r\n } else {\r\n this.classList.remove('high');\r\n }\r\n }\r\n textarea.addEventListener('input', handleTextareaChange)\r\n textarea.addEventListener('change', handleTextareaChange)\r\n }\r\n\r\n // Hide spinner preloader\r\n hideContainersSpinner();\r\n\r\n // Scroll to the bottom comments\r\n setTimeout(() => {\r\n const contentContainer = document.querySelector('.doboard_task_widget-content');\r\n contentContainer.scrollTo({\r\n top: contentContainer.scrollHeight,\r\n behavior: 'smooth'\r\n });\r\n }, 0);\r\n\r\n const sendButton = document.querySelector('.doboard_task_widget-send_message_button');\r\n if (sendButton) {\r\n this.fileUploader.init();\r\n let widgetClass = this;\r\n sendButton.addEventListener('click', async (e) => {\r\n e.preventDefault();\r\n\r\n const sendMessageContainer = sendButton.closest('.doboard_task_widget-send_message');\r\n const input = sendMessageContainer.querySelector('.doboard_task_widget-send_message_input');\r\n\r\n const commentText = input.value.trim();\r\n if (!commentText) return;\r\n\r\n // Add other fields handling here\r\n\r\n input.disabled = true;\r\n sendButton.disabled = true;\r\n\r\n let newCommentResponse = null;\r\n\r\n try {\r\n newCommentResponse = await addTaskComment(this.params, this.currentActiveTaskId, commentText);\r\n input.value = '';\r\n await this.createWidgetElement('concrete_issue');\r\n hideContainersSpinner(false);\r\n } catch (err) {\r\n alert('Error when adding a comment: ' + err.message);\r\n }\r\n\r\n if (widgetClass.fileUploader.hasFiles() && newCommentResponse !== null && newCommentResponse.hasOwnProperty('commentId')) {\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n const attachmentsSendResult = await widgetClass.fileUploader.sendAttachmentsForComment(widgetClass.params, sessionId, newCommentResponse.commentId);\r\n if (!attachmentsSendResult.success) {\r\n widgetClass.fileUploader.showError('Some files where no sent, see details in the console.');\r\n const toConsole = JSON.stringify(attachmentsSendResult);\r\n console.log(toConsole);\r\n }\r\n }\r\n\r\n input.disabled = false;\r\n sendButton.disabled = false;\r\n });\r\n }\r\n\r\n break;\r\n\r\n default:\r\n break;\r\n }\r\n\r\n const backToAllIssuesController = document.querySelector('.doboard_task_widget_return_to_all');\r\n const widgetClass = this;\r\n if ( backToAllIssuesController ) {\r\n backToAllIssuesController.addEventListener('click', function(e, self = widgetClass) {\r\n self.createWidgetElement('all_issues');\r\n });\r\n }\r\n\r\n const paperclipController = document.querySelector('.doboard_task_widget-send_message_paperclip');\r\n if ( paperclipController ) {\r\n this.fileUploader.bindPaperClipAction(paperclipController);\r\n }\r\n\r\n document.querySelector('.doboard_task_widget-close_btn')?.addEventListener('click', (e) => {\r\n this.hide();\r\n }) || '';\r\n\r\n document.querySelector('#openUserMenuButton')?.addEventListener('click', () => {\r\n this.createWidgetElement('user_menu')\r\n }) || '';\r\n\r\n document.querySelector('#doboard_task_widget-user_menu-logout_button')?.addEventListener('click', () => {\r\n logoutUserDoboard(this.params.projectToken, this.params.accountId).then(() => {this.hide()});\r\n }) || '';\r\n\r\n document.getElementById('addNewTaskButton')?.addEventListener('click', () => {\r\n spotFixShowWidget();\r\n }) || '';\r\n\r\n document.getElementById('maximizeWidgetContainer')?.addEventListener('click', () => {\r\n const container = document.querySelector('.doboard_task_widget-container');\r\n\r\n if(+localStorage.getItem('maximize') && container.classList.contains('doboard_task_widget-container-maximize')){\r\n localStorage.setItem('maximize', '0');\r\n container.classList.remove('doboard_task_widget-container-maximize');\r\n } else {\r\n localStorage.setItem('maximize', '1');\r\n container.classList.add('doboard_task_widget-container-maximize');\r\n }\r\n }) || '';\r\n\r\n document.querySelector('#doboard_task_widget-user_menu-signlog_button')?.addEventListener('click', () => {\r\n spotFixShowWidget();\r\n }) || '';\r\n\r\n document.querySelector('#spotfix_back_button')?.addEventListener('click', () => {\r\n this.createWidgetElement(this.type_name)\r\n }) || '';\r\n\r\n return widgetContainer;\r\n }\r\n\r\n bindIssuesClick() {\r\n document.querySelectorAll('.issue-item').forEach(item => {\r\n item.addEventListener('click', async () => {\r\n let nodePath = null;\r\n try {\r\n nodePath = JSON.parse(item.getAttribute('data-node-path'));\r\n } catch (error) {\r\n nodePath = null;\r\n }\r\n if (nodePath) {\r\n spotFixScrollToNodePath(nodePath);\r\n }\r\n this.currentActiveTaskId = item.getAttribute('data-task-id');\r\n await this.showOneTask();\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Show one task\r\n *\r\n * @return {Promise}\r\n *\r\n */\r\n async showOneTask() {\r\n await this.createWidgetElement('concrete_issue');\r\n const taskHighlightData = this.getTaskHighlightData(this.currentActiveTaskId)\r\n\r\n if (taskHighlightData) {\r\n spotFixRemoveHighlights();\r\n spotFixHighlightElements([taskHighlightData], this)\r\n this.positionWidgetContainer();\r\n }\r\n\r\n hideContainersSpinner(false);\r\n }\r\n\r\n /**\r\n * Load the template\r\n *\r\n * @param templateName\r\n * @param variables\r\n * @return {string}\r\n * @ToDo have to refactor templates loaded method: need to be templates included into the bundle\r\n *\r\n */\r\n loadTemplate(templateName, variables = {}) {\r\n let template = SpotFixTemplatesLoader.getTemplateCode(templateName);\r\n\r\n for (const [key, value] of Object.entries(variables)) {\r\n const placeholder = `{{${key}}}`;\r\n let replacement;\r\n\r\n // 1) For attributes we MUST use escapeHtml!\r\n // 2) Only for HTML inserts we must clean data by ksesFilter\r\n // Check if placeholder is used in an attribute context\r\n if (this.isPlaceholderInAttribute(template, placeholder)) {\r\n // For attributes, use escapeHtml to prevent XSS\r\n replacement = this.escapeHtml(String(value));\r\n } else {\r\n // For HTML content, use ksesFilter to sanitize HTML\r\n replacement = ksesFilter(String(value), {template: templateName, imgFilter: true});\r\n }\r\n\r\n template = template.replaceAll(placeholder, replacement);\r\n }\r\n\r\n return ksesFilter(template, {template: templateName});\r\n }\r\n\r\n /**\r\n * Check if a placeholder is used inside an HTML attribute\r\n * @param {string} template - The template string\r\n * @param {string} placeholder - The placeholder to check (e.g., \"{{key}}\")\r\n * @return {boolean} - True if placeholder is in an attribute context\r\n */\r\n isPlaceholderInAttribute(template, placeholder) {\r\n // Escape special regex characters in placeholder\r\n const escapedPlaceholder = placeholder.replace(/[{}]/g, '\\\\$&');\r\n\r\n // Pattern to match attribute=\"...\" or attribute='...' containing the placeholder\r\n // This regex looks for: word characters (attribute name) = \" or ' followed by content including the placeholder\r\n // Matches patterns like: src=\"{{key}}\", class=\"{{key}}\", style=\"{{key}}\", etc.\r\n const attributePattern = new RegExp(\r\n `[\\\\w-]+\\\\s*=\\\\s*[\"'][^\"']*${escapedPlaceholder}[^\"']*[\"']`,\r\n 'g'\r\n );\r\n\r\n // Check if placeholder appears in any attribute context\r\n // If it does, we'll use escapeHtml for all occurrences (safer approach)\r\n return attributePattern.test(template);\r\n }\r\n\r\n escapeHtml = (unsafe) => {\r\n return unsafe\r\n .replace(/&/g, \"&\")\r\n .replace(//g, \">\")\r\n .replace(/\"/g, \""\")\r\n .replace(/'/g, \"'\");\r\n };\r\n\r\n async getTaskCount() {\r\n if (!localStorage.getItem('spotfix_session_id')) {\r\n return {};\r\n }\r\n\r\n const projectToken = this.params.projectToken;\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n\r\n const tasksCountLS = localStorage.getItem('spotfix_tasks_count');\r\n\r\n let tasksCount;\r\n\r\n if(tasksCountLS !== 0 && !tasksCountLS){\r\n await getTasksDoboard(projectToken, sessionId, this.params.accountId, this.params.projectId);\r\n const tasks = await spotfixIndexedDB.getAll(TABLE_TASKS);\r\n const filteredTasks = tasks.filter(task => {\r\n return task.taskMeta;\r\n });\r\n tasksCount = filteredTasks.length;\r\n } else tasksCount = tasksCountLS;\r\n\r\n const taskCountElement = document.getElementById('doboard_task_widget-task_count');\r\n if ( taskCountElement ) {\r\n taskCountElement.innerText = ksesFilter(tasksCount);\r\n taskCountElement.classList.remove('hidden');\r\n }\r\n }\r\n\r\n /**\r\n * Bind events to the widget\r\n */\r\n /*bindEvents() {\r\n this.submitButton.addEventListener('click', () => this.submitTask());\r\n }*/\r\n\r\n /**\r\n * Submit the task\r\n */\r\n async submitTask(taskDetails) {\r\n if (!localStorage.getItem('spotfix_session_id')) {\r\n await registerUser(taskDetails)(this.registrationShowMessage);\r\n if ( taskDetails.userPassword ) {\r\n await loginUser(taskDetails)(this.registrationShowMessage);\r\n }\r\n }\r\n\r\n const sessionId = localStorage.getItem('spotfix_session_id');\r\n\r\n if ( ! sessionId ) {\r\n // @ToDo move this return in register block code\r\n return {needToLogin: true};\r\n }\r\n return await handleCreateTask(sessionId, taskDetails);\r\n }\r\n\r\n /**\r\n * Hide the widget\r\n */\r\n hide() {\r\n spotFixRemoveHighlights();\r\n this.createWidgetElement('wrap');\r\n\r\n }\r\n\r\n wrapElementWithSpotfixHighlight(element) {\r\n const newElement = element.cloneNode();\r\n const wrapper = document.createElement('span');\r\n wrapper.className = 'doboard_task_widget-text_selection image-highlight';\r\n\r\n element.insertAdjacentElement('beforebegin', wrapper);\r\n wrapper.appendChild(newElement);\r\n\r\n return wrapper;\r\n }\r\n\r\n /**\r\n * Get task spot data for highlighting.\r\n * @param {string|int} taskIdToSearch\r\n * @returns {object|null}\r\n */\r\n getTaskHighlightData(taskIdToSearch) {\r\n const currentTaskData = this.allTasksData.find((element) => element.taskId.toString() === taskIdToSearch.toString());\r\n if (currentTaskData && currentTaskData.taskMeta !== undefined) {\r\n let currentTaskSpotData = null;\r\n try {\r\n currentTaskSpotData = JSON.parse(currentTaskData.taskMeta);\r\n } catch (error) {\r\n currentTaskSpotData = null;\r\n }\r\n if (currentTaskSpotData !== null && typeof currentTaskSpotData === 'object') {\r\n return currentTaskSpotData;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n bindWidgetInputsInteractive() {\r\n // Customising placeholders\r\n const inputs = document.querySelectorAll('.doboard_task_widget-field');\r\n inputs.forEach(input => {\r\n if (input.value) {\r\n input.classList.add('has-value');\r\n }\r\n\r\n input.addEventListener('input', () => {\r\n if (input.value) {\r\n input.classList.add('has-value');\r\n } else {\r\n input.classList.remove('has-value');\r\n }\r\n });\r\n\r\n input.addEventListener('blur', () => {\r\n if (!input.value) {\r\n input.classList.remove('has-value');\r\n }\r\n });\r\n });\r\n\r\n // Customising accordion dropdown\r\n const accordionController = document.querySelector('.doboard_task_widget-login span');\r\n if ( accordionController ) {\r\n const context = this;\r\n accordionController.addEventListener('click', function() {\r\n this.closest('.doboard_task_widget-login').classList.toggle('active');\r\n // Scroll\r\n context.positionWidgetContainer();\r\n setTimeout(() => {\r\n const contentContainer = document.querySelector('.doboard_task_widget-content');\r\n contentContainer.scrollTo({\r\n top: contentContainer.scrollHeight,\r\n behavior: 'smooth'\r\n });\r\n }, 0);\r\n });\r\n }\r\n\r\n window.addEventListener('scroll', this.handleScroll.bind(this));\r\n window.addEventListener('resize', this.handleResize.bind(this));\r\n }\r\n\r\n registrationShowMessage(messageText, type = 'error') {\r\n const titleSpan = document.getElementById('doboard_task_widget-error_message-header');\r\n const messageDiv = document.getElementById('doboard_task_widget-error_message');\r\n const messageWrap = document.querySelector('.doboard_task_widget-message-wrapper');\r\n\r\n if (typeof messageText === 'string' && messageDiv !== null && messageWrap !== null) {\r\n messageDiv.innerText = ksesFilter(messageText);\r\n messageWrap.classList.remove('hidden');\r\n messageDiv.classList.remove('doboard_task_widget-notice_message', 'doboard_task_widget-error_message');\r\n if (type === 'notice') {\r\n titleSpan.innerText = ksesFilter('');\r\n messageWrap.classList.add('doboard_task_widget-notice_message');\r\n messageDiv.style.color = '#2a5db0';\r\n } else {\r\n titleSpan.innerText = ksesFilter('Registration error');\r\n messageWrap.classList.add('doboard_task_widget-error_message');\r\n messageDiv.style.color = 'red';\r\n }\r\n }\r\n }\r\n\r\n positionWidgetContainer() {\r\n const selection = document.querySelector('.doboard_task_widget-text_selection');\r\n const widget = document.querySelector('.doboard_task_widget')\r\n const widgetCreateIssue = document.querySelector('.doboard_task_widget-content.doboard_task_widget-create_issue')\r\n const widgetConcreteIssue = document.querySelector('.doboard_task_widget-concrete_issues-container')\r\n if ( ! ( ( widgetCreateIssue || widgetConcreteIssue ) && selection ) ) {\r\n // Skip if the widget is closed or highlight not exist\r\n return;\r\n }\r\n\r\n const scrollY = window.scrollY;\r\n const viewportHeight = window.innerHeight;\r\n\r\n const selectionAbsoluteTop = selection.getBoundingClientRect().top + scrollY;\r\n\r\n const widgetHeight = widget.offsetHeight;\r\n\r\n let top;\r\n\r\n // Check selection position\r\n if (selectionAbsoluteTop - scrollY < 0) {\r\n // 1) The selection is above the viewport - stuck the widget on the top\r\n top = 10;\r\n } else if (selectionAbsoluteTop - scrollY > viewportHeight) {\r\n // 2) The selection is below the viewport - stuck the widget on the bottom\r\n top = viewportHeight - widgetHeight - 10;\r\n } else {\r\n // 3) The selection is on viewport - the widget aligned against the selection\r\n top = selectionAbsoluteTop - scrollY\r\n if ( selectionAbsoluteTop - scrollY > viewportHeight - widgetHeight ) {\r\n // 3.1) The selection is on viewport but is below than widget height - stuck the widget on the bottom\r\n top = viewportHeight - widgetHeight - 10;\r\n }\r\n }\r\n\r\n widget.style.top = `${top}px`;\r\n widget.style.bottom = 'auto';\r\n }\r\n\r\n handleScroll() {\r\n clearTimeout(this.scrollTimeout);\r\n this.scrollTimeout = setTimeout(() => {\r\n this.positionWidgetContainer();\r\n }, 10);\r\n }\r\n\r\n handleResize() {\r\n clearTimeout(this.resizeTimeout);\r\n this.resizeTimeout = setTimeout(() => {\r\n this.positionWidgetContainer();\r\n }, 100);\r\n }\r\n\r\n /**\r\n * Check nodePath, selectedData against page source and return is the provided nodePath is correct and can be highlighted\r\n * @param taskData\r\n * @return {boolean}\r\n */\r\n isSpotHaveToBeHighlighted(taskData) {\r\n return true;\r\n }\r\n\r\n sanitizeNodePath(nodePath) {\r\n let str = Array.isArray(nodePath) ? JSON.stringify(nodePath) : String(nodePath);\r\n // Allow only digits, commas, spaces, and square brackets\r\n if (/^[\\[\\]0-9,\\s]*$/.test(str)) {\r\n return str;\r\n }\r\n return '';\r\n}\r\n}\r\n\nlet spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:\"\";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget-header-icons{display:flex}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:\"\";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:\"\";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:\"\";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:\"wght\" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E\") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E\") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:\"\"}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:\"\";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`;\nvar spotFixShowDelayTimeout = null;\r\nconst SPOTFIX_DEBUG = false;\r\nconst SPOTFIX_SHOW_DELAY = 1000;\r\n\r\nif( document.readyState !== 'loading' ) {\r\n document.addEventListener('spotFixLoaded', spotFixInit);\r\n} else {\r\n document.addEventListener('DOMContentLoaded', spotFixInit);\r\n}\r\n\r\nfunction spotFixInit() {\r\n spotfixIndexedDB.init();\r\n new SpotFixSourcesLoader();\r\n new CleanTalkWidgetDoboard({}, 'wrap');\r\n loadBotDetector()\r\n}\r\n\r\nfunction loadBotDetector() {\r\nif (document.querySelector('script[src=\"https://moderate.cleantalk.org/ct-bot-detector-wrapper.js\"]') ||\r\n document.getElementById('ct-bot-detector-script')) {\r\n return;\r\n }\r\n\r\n const script = document.createElement('script');\r\n script.src = 'https://moderate.cleantalk.org/ct-bot-detector-wrapper.js';\r\n script.async = true;\r\n script.id = 'ct-bot-detector-script';\r\n document.head.appendChild(script);\r\n}\r\n\r\ndocument.addEventListener('selectionchange', function(e) {\r\n // Do not run widget for non-document events (i.e. inputs focused)\r\n\r\n if (e.target !== document) {\r\n return;\r\n }\r\n\r\n const isWrapReviewWidgetExists = !!(document.getElementsByClassName('wrap_review')[0]);\r\n const sel = document.getSelection();\r\n\r\n if ((!sel || sel.toString() === \"\") && isWrapReviewWidgetExists) {\r\n new CleanTalkWidgetDoboard({}, 'wrap')\r\n return;\r\n }\r\n\r\n if (spotFixShowDelayTimeout) {\r\n clearTimeout(spotFixShowDelayTimeout);\r\n }\r\n\r\n spotFixShowDelayTimeout = setTimeout(() => {\r\n const selection = window.getSelection();\r\n if (\r\n selection.type === 'Range'\r\n ) {\r\n // Check if selection is inside the widget\r\n let anchorNode = selection.anchorNode;\r\n let focusNode = selection.focusNode;\r\n if (spotFixIsInsideWidget(anchorNode) || spotFixIsInsideWidget(focusNode)) {\r\n return;\r\n }\r\n const selectedData = spotFixGetSelectedData(selection);\r\n\r\n if ( selectedData ) {\r\n // spotFixOpenWidget(selectedData, 'create_issue');\r\n spotFixOpenWidget(selectedData, 'wrap_review');\r\n }\r\n }\r\n }, SPOTFIX_SHOW_DELAY);\r\n});\r\n\r\n\r\n/**\r\n * Shows the spot fix widget.\r\n */\r\nfunction spotFixShowWidget() {\r\n new CleanTalkWidgetDoboard(null, 'create_issue');\r\n}\r\n\r\n/**\r\n * Check if a node is inside the task widget.\r\n * @param {*} node\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsInsideWidget(node) {\r\n if (!node) return false;\r\n let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n while (el) {\r\n if (el.classList && el.classList.contains('doboard_task_widget')) {\r\n return true;\r\n }\r\n el = el.parentElement;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Open the widget to create a task.\r\n * @param {*} selectedData\r\n * @param {*} type\r\n */\r\nfunction spotFixOpenWidget(selectedData, type) {\r\n if (selectedData) {\r\n new CleanTalkWidgetDoboard(selectedData, type);\r\n }\r\n}\r\n\r\n/**\r\n * Write message into the console.\r\n *\r\n * @param {string} message\r\n */\r\nfunction spotFixDebugLog(message) {\r\n if ( SPOTFIX_DEBUG ) {\r\n console.log(message);\r\n }\r\n}\r\n\r\nfunction hideContainersSpinner() {\r\n const spinners = document.getElementsByClassName('doboard_task_widget-spinner_wrapper_for_containers');\r\n if (spinners.length > 0) {\r\n for (let i = 0; i < spinners.length ; i++) {\r\n spinners[i].style.display = 'none';\r\n }\r\n }\r\n const containerClassesToShow = ['doboard_task_widget-all_issues-container', 'doboard_task_widget-concrete_issues-container'];\r\n for (let i = 0; i < containerClassesToShow.length ; i++) {\r\n const containers = document.getElementsByClassName(containerClassesToShow[i]);\r\n if (containers.length > 0) {\r\n for (let i = 0; i < containers.length ; i++) {\r\n containers[i].style.display = 'block';\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction getTaskFullDetails(tasksDetails, taskId) {\r\n const comments = tasksDetails.comments.filter(comment => {\r\n return comment?.taskId?.toString() === taskId?.toString()\r\n });\r\n const users = tasksDetails.users;\r\n // Last comment\r\n let lastComment = comments.length > 0 ? comments[0] : null;\r\n // Author of the last comment\r\n let author = null;\r\n if (lastComment && users && users.length > 0) {\r\n author = users.find(u => String(u.user_id) === String(lastComment.userId));\r\n }\r\n // Format date\r\n let date = '', time = '';\r\n if (lastComment) {\r\n const dt = formatDate(lastComment.commentDate);\r\n date = dt.date;\r\n time = dt.time;\r\n }\r\n // Get the avatar and the name through separate functions\r\n let avatarSrc = getAvatarSrc(author);\r\n let authorName = getAuthorName(author);\r\n\r\n return {\r\n taskId: taskId,\r\n taskAuthorAvatarImgSrc: avatarSrc,\r\n taskAuthorName: authorName,\r\n lastMessageText: lastComment ? lastComment.commentBody : 'No messages yet',\r\n lastMessageTime: time,\r\n issueTitle: comments.length > 0 ? comments[0].issueTitle : 'No Title',\r\n issueComments: comments\r\n .sort((a, b) => {\r\n return new Date(a.commentDate) - new Date(b.commentDate);\r\n })\r\n .map(comment => {\r\n const {date, time} = formatDate(comment.commentDate);\r\n let author = null;\r\n if (users && users.length > 0) {\r\n author = users.find(u => String(u.user_id) === String(comment.userId));\r\n }\r\n return {\r\n commentAuthorAvatarSrc: getAvatarSrc(author),\r\n commentAuthorName: getAuthorName(author),\r\n commentBody: comment.commentBody,\r\n commentDate: date,\r\n commentTime: time,\r\n commentUserId: comment.userId || 'Unknown User',\r\n };\r\n })\r\n };\r\n}\r\n\r\nfunction getAvatarData(authorDetails) {\r\n let avatarStyle;\r\n let avatarCSSClass;\r\n let taskAuthorInitials =\r\n authorDetails.taskAuthorName && authorDetails.taskAuthorName != 'Anonymous'\r\n ? authorDetails.taskAuthorName.trim().charAt(0).toUpperCase()\r\n : null;\r\n let initialsClass = 'doboard_task_widget-avatar-initials';\r\n if (authorDetails.taskAuthorAvatarImgSrc === null && taskAuthorInitials !== null) {\r\n avatarStyle = 'display: flex;background-color: #f8de7e;justify-content: center;align-items: center;';\r\n avatarCSSClass = 'doboard_task_widget-avatar_container';\r\n }\r\n if (authorDetails.taskAuthorAvatarImgSrc === null && taskAuthorInitials === null) {\r\n avatarStyle = `background-image:url(\\'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');`;\r\n avatarCSSClass = 'doboard_task_widget-avatar_container';\r\n initialsClass += ' doboard_task_widget-hidden_element';\r\n }\r\n if (authorDetails.taskAuthorAvatarImgSrc !== null) {\r\n avatarStyle = `background-image:url(\\'${authorDetails.taskAuthorAvatarImgSrc}\\');`;\r\n avatarCSSClass = 'doboard_task_widget-avatar_container';\r\n initialsClass = 'doboard_task_widget-hidden_element';\r\n }\r\n return {\r\n avatarStyle: avatarStyle,\r\n avatarCSSClass: avatarCSSClass,\r\n taskAuthorInitials: taskAuthorInitials,\r\n initialsClass: initialsClass\r\n }\r\n}\r\n\r\n/**\r\n * Return first found updated task ID or false if no tasks were updated\r\n * @param allTasksData\r\n * @returns {string[]|false}\r\n */\r\nfunction isAnyTaskUpdated(allTasksData) {\r\n let result = false;\r\n\r\n const updatedtasksIDS = [];\r\n\r\n for (let i = 0; i < allTasksData.length; i++) {\r\n const currentStateOfTask = allTasksData[i];\r\n const issuerId = localStorage.getItem('spotfix_user_id');\r\n if (\r\n currentStateOfTask.taskId &&\r\n currentStateOfTask.taskLastUpdate &&\r\n currentStateOfTask.taskCreatorTaskUser.toString() === issuerId.toString()\r\n ) {\r\n result = storageCheckTaskUpdate(currentStateOfTask.taskId, currentStateOfTask.taskLastUpdate);\r\n if (result) {\r\n updatedtasksIDS.push(currentStateOfTask.taskId.toString());\r\n }\r\n }\r\n }\r\n\r\n return updatedtasksIDS.length === 0 ? false : updatedtasksIDS;\r\n}\r\n\r\n/**\r\n * Check if any of the tasks has updates from site owner (not from the current user and not anonymous)\r\n * @returns {Promise}\r\n */\r\nasync function checkIfTasksHasSiteOwnerUpdates(allTasksData, params) {\r\n const updatedTaskIDs = isAnyTaskUpdated(allTasksData);\r\n let result = false;\r\n if (!updatedTaskIDs) {\r\n return false;\r\n }\r\n for (let i = 0; i < updatedTaskIDs.length; i++) {\r\n const updatedTaskId = updatedTaskIDs[i];\r\n if (typeof updatedTaskId === 'string') {\r\n const updatedTaskData = await getTasksFullDetails(params, [updatedTaskId]);\r\n if (updatedTaskData.comments) {\r\n const lastMessage = updatedTaskData.comments[0];\r\n if (\r\n lastMessage.commentUserId !== undefined &&\r\n lastMessage.commentUserId !== localStorage.getItem('spotfix_user_id') &&\r\n lastMessage.commentAuthorName !== 'Anonymous'\r\n ) {\r\n storageAddUnreadUpdateForTaskID(updatedTaskId);\r\n result = true;\r\n }\r\n }\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Check if the selection is correct - do not allow to select all page, or several different nesting nodes, or something else\r\n * @param selection\r\n * @return {boolean}\r\n */\r\nfunction isSelectionCorrect(selection) {\r\n return true;\r\n}\r\n\r\n/**\r\n * Sanitize HTML\r\n * @param {*} html\r\n * @param {*} options\r\n * @returns\r\n */\r\nfunction ksesFilter(html, options = false) {\r\n let allowedTags = {\r\n a: true,\r\n b: true,\r\n i: true,\r\n strong: true,\r\n em: true,\r\n ul: true,\r\n ol: true,\r\n li: true,\r\n p: true,\r\n s: true,\r\n br: true,\r\n span: true,\r\n blockquote: true,\r\n pre: true,\r\n div: true,\r\n img: true,\r\n input: true,\r\n label: true,\r\n textarea: true,\r\n button: true,\r\n blockquote: true,\r\n pre: true,\r\n details: true,\r\n summary: true,\r\n };\r\n let allowedAttrs = {\r\n a: ['href', 'title', 'target', 'rel', 'style', 'class'],\r\n span: ['style', 'class', 'id'],\r\n p: ['style', 'class'],\r\n div: ['style', 'class', 'id', 'data-node-path', 'data-task-id'],\r\n img: ['src', 'alt', 'title', 'class', 'style', 'width', 'height'],\r\n input: ['type', 'class', 'style', 'id', 'multiple', 'accept', 'value'],\r\n label: ['for', 'class', 'style'],\r\n textarea: ['class', 'id', 'style', 'rows', 'cols', 'readonly', 'required', 'name'],\r\n button: ['type', 'class', 'style', 'id'],\r\n details: ['class', 'style', 'open'],\r\n summary: ['class', 'style'],\r\n };\r\n\r\n if (options && options.template === 'list_issues') {\r\n allowedTags = { ...allowedTags, br: false };\r\n }\r\n\r\n const parser = new DOMParser();\r\n const doc = parser.parseFromString(html, 'text/html');\r\n function clean(node) {\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const tag = node.tagName.toLowerCase();\r\n\r\n if (options) {\r\n if (allowedTags[tag]) {\r\n // Special handling for images in 'concrete_issue_day_content' template (wrap img in link always)\r\n if (tag === 'img' && options.template === 'concrete_issue_day_content' && options.imgFilter) {\r\n const src = node.getAttribute('src') || '';\r\n const alt = node.getAttribute('alt') || '[image]';\r\n const link = doc.createElement('a');\r\n link.href = src;\r\n link.target = '_blank';\r\n link.className = 'doboard_task_widget-img-link';\r\n const img = doc.createElement('img');\r\n img.src = src;\r\n img.alt = alt;\r\n img.className = 'doboard_task_widget-comment_body-img-strict';\r\n link.appendChild(img);\r\n node.parentNode.insertBefore(link, node);\r\n node.remove();\r\n return;\r\n }\r\n }\r\n\r\n if (!allowedTags[tag]) {\r\n // Special handling for images in 'list_issues' template\r\n if (tag === 'img' && options.template === 'list_issues' && options.imgFilter) {\r\n const src = node.getAttribute('src') || '';\r\n const alt = node.getAttribute('alt') || '[image]';\r\n const link = doc.createElement('a');\r\n link.href = src;\r\n link.target = '_blank';\r\n link.textContent = alt;\r\n node.parentNode.insertBefore(link, node);\r\n }\r\n node.remove();\r\n return;\r\n }\r\n }\r\n\r\n // Remove disallowed attributes\r\n [...node.attributes].forEach(attr => {\r\n const attrName = attr.name.toLowerCase();\r\n if (!allowedAttrs[tag]?.includes(attrName) ||\r\n attrName.startsWith('on') || // Remove event handlers\r\n attr.value.toLowerCase().includes('javascript:')) {\r\n node.removeAttribute(attr.name);\r\n }\r\n });\r\n }\r\n // Recursively clean children\r\n [...node.childNodes].forEach(clean);\r\n }\r\n [...doc.body.childNodes].forEach(clean);\r\n return doc.body.innerHTML;\r\n}\r\n\n/**\r\n * SELECTION will be grouped into three types:\r\n * 1 - Simple text within a single tag\r\n * 2 - Image tags\r\n * 3 - Any tag containing nested content\r\n * Each type will be processed differently.\r\n */\r\nconst SPOTFIX_SELECTION_TYPE_TEXT = 'text';\r\nconst SPOTFIX_SELECTION_TYPE_IMG = 'image';\r\nconst SPOTFIX_SELECTION_TYPE_ELEMENT = 'element';\r\n\r\n/**\r\n * Determines the type of selection\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {string|null} Selection type\r\n */\r\nfunction spotFixGetSelectionType(selection) {\r\n const range = selection.getRangeAt(0);\r\n const commonAncestor = range.commonAncestorContainer;\r\n\r\n // Case 1: Image selection\r\n if (spotFixGetSelectedImage(selection)) {\r\n return SPOTFIX_SELECTION_TYPE_IMG;\r\n }\r\n\r\n // Case 2: Element with nested content\r\n if (commonAncestor.nodeType === Node.ELEMENT_NODE &&\r\n commonAncestor.childNodes.length > 1 &&\r\n range.toString().trim() === '' &&\r\n range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE) {\r\n return SPOTFIX_SELECTION_TYPE_ELEMENT;\r\n }\r\n\r\n // Case 3: Simple text\r\n const hasTextContent = range.toString().trim().length > 0;\r\n const isTextNode = commonAncestor.nodeType === Node.TEXT_NODE;\r\n const isCollapsed = range.collapsed;\r\n\r\n if (hasTextContent && (isTextNode || !isCollapsed)) {\r\n return SPOTFIX_SELECTION_TYPE_TEXT;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extracts selection data from DOM Selection object\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {Object|null} Selection data with text, positions, URL and node path OR null (nothing)\r\n */\r\nfunction spotFixGetSelectedData(selection) {\r\n // Prechecks:\r\n // Selection not provided\r\n if (!selection) {spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection not provided`'); return null; }\r\n // Range not provided\r\n if (selection.rangeCount === 0) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Range not provided`'); return null; }\r\n // Several ranges provided\r\n if (selection.rangeCount > 1) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Several ranges provided`'); return null; }\r\n\r\n const range = selection.getRangeAt(0);\r\n // Selection must be within a single DOM element.\r\n if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }\r\n\r\n // FIRST - check selection type\r\n const selectionType = spotFixGetSelectionType(selection);\r\n\r\n // Selection type not determined\r\n if (!selectionType) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection type not determined`'); return null; }\r\n\r\n // SECOND - generate selectedData for each selectionType\r\n let selectedText = '';\r\n let startSelectPosition = 0;\r\n let endSelectPosition = 0;\r\n let nodePath = '';\r\n let imageUrl = '';\r\n\r\n const commonNode = range.commonAncestorContainer;\r\n\r\n switch (selectionType) {\r\n case SPOTFIX_SELECTION_TYPE_TEXT:\r\n if (range.toString().trim().length === 0) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection text is empty`');\r\n return null;\r\n }\r\n const commonNodeElement = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n selectedText = range.toString();\r\n startSelectPosition = range.startOffset;\r\n endSelectPosition = range.endOffset;\r\n if ( startSelectPosition === 0 && selectedText.length > endSelectPosition ) {\r\n endSelectPosition = selectedText.length;\r\n }\r\n nodePath = spotFixCalculateNodePath(commonNodeElement);\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_IMG:\r\n const imgElement = range.startContainer;\r\n const selectedImage = spotFixGetSelectedImage(selection);\r\n selectedText = `Image (${selectedImage.alt ? selectedImage.alt : 'no description'})`;\r\n nodePath = spotFixCalculateNodePath(selectedImage);\r\n // For images, positions represent the image element position in parent\r\n startSelectPosition = Array.from(imgElement.parentNode.children).indexOf(imgElement);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_ELEMENT:\r\n const element = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n if (element.childNodes.length <= 1) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection have not inner data`');\r\n return null;\r\n }\r\n selectedText = element.textContent || '';\r\n nodePath = spotFixCalculateNodePath(element);\r\n // For elements, positions represent the element's position in parent\r\n startSelectPosition = Array.from(element.parentNode.children).indexOf(element);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n }\r\n\r\n // Get page URL\r\n const pageURL = window.location.href;\r\n\r\n return {\r\n startSelectPosition,\r\n endSelectPosition,\r\n selectedText: selectedText.trim(),\r\n pageURL,\r\n nodePath,\r\n selectionType,\r\n imageUrl: selectionType === SPOTFIX_SELECTION_TYPE_IMG ? imageUrl : ''\r\n };\r\n}\r\n\r\n/**\r\n * Highlight elements.\r\n * @param {[object]} spotsToBeHighlighted\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightElements(spotsToBeHighlighted, widgetInstance) {\r\n\r\n if (spotsToBeHighlighted.length === 0) return;\r\n\r\n const elementsMap = new Map();\r\n\r\n // Grouping elements with validation\r\n spotsToBeHighlighted.forEach(spot => {\r\n // nodePath validating: is array\r\n if (!spot?.nodePath || !Array.isArray(spot?.nodePath)) {\r\n spotFixDebugLog('Invalid spot: missing or invalid nodePath: ' + spot);\r\n return;\r\n }\r\n\r\n // nodePath validating: is valid indexes list\r\n if (!this.spotFixIsValidNodePath(spot.nodePath)) {\r\n spotFixDebugLog('Invalid nodePath format: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n const element = spotFixRetrieveNodeFromPath(spot.nodePath);\r\n if (!element) {\r\n spotFixDebugLog('Element not found for path: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n if ( ! spot.selectionType ) {\r\n // @ToDo need to apply backward capability here\r\n // just `spot.selectionType = 'text';` is not able, this opens ability to unauthorized modify website content\r\n spotFixDebugLog('Selection type is not provided.');\r\n return;\r\n }\r\n\r\n // selectionType parameter validating\r\n if (\r\n spot.selectionType &&\r\n ![\r\n SPOTFIX_SELECTION_TYPE_TEXT,\r\n SPOTFIX_SELECTION_TYPE_IMG,\r\n SPOTFIX_SELECTION_TYPE_ELEMENT\r\n ].includes(spot.selectionType)\r\n ) {\r\n spotFixDebugLog('Invalid selection type: ' + spot.selectionType);\r\n return;\r\n }\r\n\r\n if (!elementsMap.has(element)) {\r\n elementsMap.set(element, []);\r\n }\r\n elementsMap.get(element).push(spot);\r\n });\r\n\r\n elementsMap.forEach((spots, element) => {\r\n const selectionType = spots[0].selectionType;\r\n\r\n // MAIN LOGIC: highlight for the different types\r\n switch (selectionType) {\r\n case 'image':\r\n this.spotFixHighlightImageElement(element);\r\n break;\r\n\r\n case 'element':\r\n this.spotFixHighlightNestedElement(element);\r\n break;\r\n\r\n case 'text':\r\n this.spotFixHighlightTextInElement(element, spots, widgetInstance);\r\n break;\r\n\r\n default:\r\n spotFixDebugLog('Unknown selection type: ' + selectionType);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Highlight image element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightImageElement(element) {\r\n if (element.tagName !== 'IMG') {\r\n spotFixDebugLog('Expected IMG element for image highlight, got: ' + element.tagName);\r\n return;\r\n }\r\n element.classList.add('doboard_task_widget-image_selection');\r\n}\r\n\r\n/**\r\n * Highlight nested element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightNestedElement(element) {\r\n element.classList.add('doboard_task_widget-element_selection');\r\n}\r\n\r\n/**\r\n * Highlight text in element with span wrapping\r\n * @param {Element} element\r\n * @param {Array} spots\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightTextInElement(element, spots,widgetInstance) {\r\n let tooltipTitleText = '';\r\n if (spots[0].isFixed) {\r\n tooltipTitleText = `This issue already fixed.`;\r\n } else {\r\n tooltipTitleText = `We are already working on this issue.`;\r\n }\r\n\r\n const tooltip = `
\r\n \r\n \r\n
${tooltipTitleText}
\r\n
You can see history Here
\r\n
\r\n
`;\r\n\r\n const spotfixHighlightOpen = `${tooltip}`;\r\n const spotfixHighlightClose = ``;\r\n\r\n let text = element.textContent;\r\n const spotSelectedText = spots[0].selectedText;\r\n\r\n // meta.selectedText can not be empty string\r\n if ( ! spotSelectedText ) {\r\n spotFixDebugLog('Provided metadata is invalid.');\r\n return;\r\n }\r\n\r\n const markers = [];\r\n\r\n // Mark positions for inserting\r\n spots.forEach(spot => {\r\n // Validating positions\r\n const startPos = parseInt(spot.startSelectPosition) || 0;\r\n const endPos = parseInt(spot.endSelectPosition) || 0;\r\n\r\n if (startPos < 0 || endPos > text.length || startPos > endPos) {\r\n spotFixDebugLog('Invalid text positions: ' + spot);\r\n return;\r\n }\r\n\r\n markers.push({ position: startPos, type: 'start' });\r\n markers.push({ position: endPos, type: 'end' });\r\n });\r\n\r\n if (markers.length === 0) return;\r\n\r\n // Sort markers backward\r\n markers.sort((a, b) => b.position - a.position);\r\n\r\n // Check here that element (from meta.nodePath) contains same inner text as in meta.selectedText\r\n // Is the `text` in the element equal to the selected text `spotSelectedText`\r\n if ( text.slice(markers[1].position, markers[0].position) !== spotSelectedText ) {\r\n spotFixDebugLog('It is not allow to highlight element by provided metadata.');\r\n return;\r\n }\r\n\r\n let result = text;\r\n markers.forEach(marker => {\r\n const insertText = marker.type === 'start'\r\n ? spotfixHighlightOpen\r\n : spotfixHighlightClose;\r\n\r\n result = result.slice(0, marker.position) + insertText + result.slice(marker.position);\r\n });\r\n\r\n // Safety HTML insert\r\n try {\r\n element.innerHTML = ksesFilter(result);\r\n document.querySelectorAll('.doboard_task_widget-see-task').forEach(link => {\r\n link.addEventListener('click', (e) => {\r\n\r\n e.preventDefault();\r\n const classList = link.className.split(' ');\r\n const idClass = classList.find(cls => cls.includes('__task-id-'));\r\n let taskId = null;\r\n if (idClass) {\r\n taskId = idClass.split('__task-id-')[1];\r\n }\r\n if (taskId) {\r\n widgetInstance.currentActiveTaskId = taskId;\r\n widgetInstance.showOneTask();\r\n }\r\n });\r\n });\r\n } catch (error) {\r\n spotFixDebugLog('Error updating element content: ' + error);\r\n }\r\n}\r\n\r\n/**\r\n * Scroll to an element by tag, class, and text content\r\n * @param {array} path - The path to the element\r\n * @return {boolean} - True if the element was found and scrolled to, false otherwise\r\n */\r\nfunction spotFixScrollToNodePath(path) {\r\n const node = spotFixRetrieveNodeFromPath(path);\r\n if (node && node.scrollIntoView) {\r\n node.scrollIntoView({ behavior: 'smooth', block: 'center' });\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction spotFixRemoveHighlights() {\r\n const textSelectionclassName = 'doboard_task_widget-text_selection';\r\n const spans = document.querySelectorAll('.' + textSelectionclassName);\r\n const affectedParents = new Set(); // Track unique parents\r\n\r\n spans.forEach(span => {\r\n const parent = span.parentNode;\r\n affectedParents.add(parent); // Mark parent as affected\r\n const tooltip = span.querySelector('.doboard_task_widget-text_selection_tooltip');\r\n if (tooltip) tooltip.remove();\r\n\r\n // Move all child nodes out of the span and into the parent\r\n while (span.firstChild) {\r\n parent.insertBefore(span.firstChild, span);\r\n }\r\n parent.removeChild(span);\r\n });\r\n\r\n // Normalize all affected parents to merge adjacent text nodes\r\n affectedParents.forEach(parent => parent.normalize());\r\n\r\n const elementSelectionClassName = 'doboard_task_widget-element_selection';\r\n const elements = document.querySelectorAll(`.${elementSelectionClassName}`);\r\n elements.forEach(element => {\r\n element.classList.remove(elementSelectionClassName);\r\n });\r\n const imageSelectionClassName = 'doboard_task_widget-image_selection';\r\n const images = document.querySelectorAll(`.${imageSelectionClassName}`);\r\n images.forEach(element => {\r\n element.classList.remove(imageSelectionClassName);\r\n });\r\n}\r\n\r\n/**\r\n * Validate nodePath as array of indices\r\n * @param {Array} nodePath\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsValidNodePath(nodePath) {\r\n if (!Array.isArray(nodePath)) return false;\r\n if (nodePath.length === 0) return false;\r\n\r\n return nodePath.every(index => {\r\n return Number.isInteger(index) && index >= 0 && index < 1000;\r\n });\r\n}\r\n\r\n/**\r\n * Try to find selected image in selection.\r\n * @param selection\r\n * @returns {Node|*|null}\r\n */\r\nfunction spotFixGetSelectedImage(selection) {\r\n\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\r\n return null;\r\n }\r\n\r\n const range = selection.getRangeAt(0);\r\n\r\n // Is current end container IMG\r\n if (range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE &&\r\n range.startContainer.tagName === 'IMG') {\r\n return range.startContainer;\r\n }\r\n\r\n // Get img in the range\r\n const walker = document.createTreeWalker(\r\n range.commonAncestorContainer,\r\n NodeFilter.SHOW_ELEMENT,\r\n {\r\n acceptNode: function(node) {\r\n return node.tagName === 'IMG' &&\r\n spotFixIsElementInRange(node, range) ?\r\n NodeFilter.FILTER_ACCEPT :\r\n NodeFilter.FILTER_REJECT;\r\n }\r\n }\r\n );\r\n\r\n let imgNode = walker.nextNode();\r\n if (imgNode) {\r\n return imgNode;\r\n }\r\n\r\n // start/end containers\r\n const startElement = spotFixGetElementFromNode(range.startContainer);\r\n const endElement = spotFixGetElementFromNode(range.endContainer);\r\n\r\n // If selection starts on image\r\n if (startElement && startElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(startElement, range)) {\r\n return startElement;\r\n }\r\n\r\n if (endElement && endElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(endElement, range)) {\r\n return endElement;\r\n }\r\n\r\n // 4. Get closest IMG\r\n const nearbyElements = spotFixFindNearbyElements(range);\r\n for (const element of nearbyElements) {\r\n if (element.tagName === 'IMG') {\r\n return element;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction spotFixIsElementInRange(element, range) {\r\n const elementRange = document.createRange();\r\n elementRange.selectNode(element);\r\n return range.compareBoundaryPoints(Range.START_TO_START, elementRange) <= 0 &&\r\n range.compareBoundaryPoints(Range.END_TO_END, elementRange) >= 0;\r\n}\r\n\r\nfunction spotFixIsElementPartiallySelected(element, range) {\r\n const elementRect = element.getBoundingClientRect();\r\n const rangeRect = range.getBoundingClientRect();\r\n\r\n // bounding rectangles is crossed\r\n return !(elementRect.right < rangeRect.left ||\r\n elementRect.left > rangeRect.right ||\r\n elementRect.bottom < rangeRect.top ||\r\n elementRect.top > rangeRect.bottom);\r\n}\r\n\r\nfunction spotFixGetElementFromNode(node) {\r\n return node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n}\r\n\r\n/**\r\n * Find nearby elements in the range.\r\n * @param range\r\n * @returns {*[]}\r\n */\r\nfunction spotFixFindNearbyElements(range) {\r\n const elements = [];\r\n const container = range.commonAncestorContainer;\r\n\r\n // search elements\r\n const previousElement = container.previousElementSibling;\r\n const nextElement = container.nextElementSibling;\r\n\r\n if (previousElement) {\r\n elements.push(previousElement);\r\n }\r\n if (nextElement) {\r\n elements.push(nextElement);\r\n }\r\n\r\n // Also check child container\r\n if (container.nodeType === Node.ELEMENT_NODE) {\r\n const children = container.children;\r\n for (let i = 0; i < children.length; i++) {\r\n if (spotFixIsElementPartiallySelected(children[i], range)) {\r\n elements.push(children[i]);\r\n }\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Calculate the path of a DOM node\r\n *\r\n * @param {Node} node\r\n * @return {int[]}\r\n */\r\nfunction spotFixCalculateNodePath(node) {\r\n let path = [];\r\n while (node) {\r\n let index = 0;\r\n let sibling = node.previousSibling;\r\n while (sibling) {\r\n if (sibling.nodeType === 1) {\r\n index++;\r\n }\r\n sibling = sibling.previousSibling;\r\n }\r\n path.unshift(index);\r\n node = node.parentNode;\r\n }\r\n\r\n // Hard fix - need to remove first element to work correctly\r\n path.shift();\r\n\r\n return path;\r\n}\r\n\r\n/**\r\n * Retrieve a DOM node from a path\r\n *\r\n * @param {int[]} path\r\n * @return {*|null}\r\n */\r\nfunction spotFixRetrieveNodeFromPath(path) {\r\n // @ToDo check if the path is correct\r\n if ( ! path ) {\r\n return null;\r\n }\r\n\r\n let node = document;\r\n for (let i = 0; i < path.length; i++) {\r\n node = node.children[path[i]];\r\n if ( ! node ) {\r\n return null;\r\n }\r\n }\r\n return node;\r\n}\r\n\n/**\r\n * Return bool if widget is closed in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetWidgetIsClosed() {\r\n return localStorage.getItem('spotfix_widget_is_closed') === '1';\r\n}\r\n\r\n/**\r\n * Return bool if widget closed state is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageWidgetCloseIsSet() {\r\n return localStorage.getItem('spotfix_widget_is_closed') !== null;\r\n}\r\n\r\n/**\r\n * Save widget closed state\r\n * @param visible\r\n */\r\nfunction storageSetWidgetIsClosed(visible) {\r\n localStorage.setItem('spotfix_widget_is_closed', visible ? '1' : '0');\r\n}\r\n\r\n/**\r\n * Return bool if user is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetUserIsDefined() {\r\n return localStorage.getItem('spotfix_user_id') !== null;\r\n}\r\n\r\n/**\r\n * Save data for updates check\r\n * @param tasks\r\n */\r\nfunction storageSaveTasksUpdateData(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n\r\n tasks.forEach(task => {\r\n if (task.taskId && task.taskLastUpdate) {\r\n storedTasks[task.taskId] = {\r\n taskId: task.taskId,\r\n taskLastUpdate: task.taskLastUpdate\r\n };\r\n }\r\n });\r\n\r\n localStorage.setItem('spotfix_task_updates', JSON.stringify(storedTasks));\r\n}\r\n\r\nfunction storageSaveTasksCount(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n const count = tasks.filter(task => {\r\n return task.taskMeta;\r\n })?.length;\r\n\r\n localStorage.setItem('spotfix_tasks_count', `${count}`);\r\n}\r\n\r\n/**\r\n * Check if a specific task has been updated since last check\r\n * @param taskId\r\n * @param currentLastUpdate\r\n * @returns {boolean|null}\r\n */\r\nfunction storageCheckTaskUpdate(taskId, currentLastUpdate) {\r\n if (!taskId || !currentLastUpdate) {\r\n return null;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n const storedTask = storedTasks[taskId];\r\n\r\n if (!storedTask) {\r\n return false;\r\n }\r\n\r\n const storedUpdate = new Date(storedTask.taskLastUpdate);\r\n const currentUpdate = new Date(currentLastUpdate);\r\n return currentUpdate > storedUpdate;\r\n}\r\n\r\n/**\r\n * Add unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageAddUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n if (!storedUnread.includes(taskId)) {\r\n storedUnread.push(taskId);\r\n }\r\n\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Remove unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageRemoveUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n storedUnread = storedUnread.filter(id => id !== taskId);\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Check if there are any unread updates\r\n * @returns {boolean}\r\n */\r\nfunction storageTasksHasUnreadUpdates() {\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.length > 0;\r\n}\r\n\r\n/**\r\n * Check if a specific task has unread updates\r\n * @param taskId\r\n * @returns {boolean}\r\n */\r\nfunction storageProvidedTaskHasUnreadUpdates(taskId) {\r\n if (!taskId) {\r\n return false;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.includes(taskId.toString());\r\n}\r\n\r\nfunction storageSaveSpotfixVersion (version) {\r\n localStorage.setItem('spotfix_app_version', `${version}`);\r\n}\r\n\r\nfunction clearLocalstorageOnLogout () {\r\n localStorage.removeItem('spotfix_email');\r\n localStorage.removeItem('spotfix_session_id');\r\n localStorage.removeItem('spotfix_user_id');\r\n localStorage.setItem('spotfix_widget_is_closed', '1');\r\n}\r\n\n/**\r\n * File uploader handler for managing file attachments with validation and upload capabilities\r\n */\r\nclass FileUploader {\r\n /**\r\n * Create a new FileUploader instance\r\n * @param {function} escapeHtmlHandler - Function to escape HTML strings for security\r\n */\r\n constructor(escapeHtmlHandler) {\r\n /** @type {Array<{id: string, file: File}>} */\r\n this.files = [];\r\n\r\n /** @type {number} Maximum allowed file size in bytes */\r\n this.maxFileSize = 5 * 1024 * 1024; // 5MB\r\n\r\n /** @type {number} Maximum total size for all files in bytes */\r\n this.maxTotalSize = 25 * 1024 * 1024; // 25MB\r\n\r\n /** @type {number} Maximum number of files allowed */\r\n this.maxFiles = 5;\r\n\r\n /** @type {string[]} Allowed MIME types for files */\r\n this.allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'text/plain', 'application/msword'];\r\n\r\n /** @type {function} HTML escaping function for XSS protection */\r\n this.escapeHtmlHandler = escapeHtmlHandler;\r\n\r\n /** @type {string[]} File size units for display */\r\n this.SIZE_UNITS = ['Bytes', 'KB', 'MB', 'GB'];\r\n }\r\n\r\n /**\r\n * Initialize elements and bindings. Should be called only for comments.\r\n * @returns {void}\r\n */\r\n init() {\r\n this.initializeElements();\r\n this.bindFilesInputChange();\r\n }\r\n\r\n /**\r\n * Define widget elements to work with uploader.\r\n * @returns {void}\r\n */\r\n initializeElements() {\r\n /** @type {HTMLInputElement|null} */\r\n this.fileInput = document.getElementById('doboard_task_widget__file-upload__file-input-button');\r\n\r\n /** @type {HTMLElement|null} */\r\n this.fileList = document.getElementById('doboard_task_widget__file-upload__file-list');\r\n\r\n this.uploaderWrapper = document.getElementById('doboard_task_widget__file-upload__wrapper');\r\n\r\n /** @type {HTMLElement|null} */\r\n this.errorMessage = document.getElementById('doboard_task_widget__file-upload__error');\r\n\r\n if (!this.fileInput || !this.fileList || !this.errorMessage || this.uploaderWrapper) {\r\n console.warn('File uploader elements not found');\r\n }\r\n }\r\n\r\n /**\r\n * Define hidden file input change to run uploader logic.\r\n * @returns {void}\r\n */\r\n bindFilesInputChange() {\r\n if (this.fileInput) {\r\n this.fileInput.addEventListener('change', (e) => this.handleFileInputChange(e));\r\n }\r\n }\r\n\r\n /**\r\n * Bind action to paperclip button.\r\n * @param {HTMLElement} element - The paperclip button element\r\n * @returns {void}\r\n */\r\n bindPaperClipAction(element) {\r\n element.addEventListener('click', (e) => {\r\n e.preventDefault();\r\n if (this.fileInput) {\r\n this.fileInput.click();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Handle file input change event\r\n * @param {Event} event - File input change event\r\n * @returns {void}\r\n */\r\n handleFileInputChange(event) {\r\n this.clearError();\r\n\r\n const selectedFiles = Array.from(event.target.files);\r\n if (this.files.length + selectedFiles.length > this.maxFiles) {\r\n this.showError(`Maximum ${this.maxFiles} files can be attached.`);\r\n return;\r\n }\r\n const validFiles = selectedFiles.filter(file => this.validateFile(file));\r\n\r\n validFiles.forEach(file => this.addFile(file));\r\n\r\n // Reset input to allow selecting same files again\r\n event.target.value = '';\r\n\r\n // show wrapper\r\n this.uploaderWrapper.style.display = 'block';\r\n }\r\n\r\n /**\r\n * Validate a file against upload constraints\r\n * @param {File} file - File to validate\r\n * @returns {boolean} True if file is valid, false otherwise\r\n */\r\n validateFile(file) {\r\n // Check file size\r\n if (file.size > this.maxFileSize) {\r\n this.showError(`File \"${file.name}\" is too large. Maximum size: ${this.formatFileSize(this.maxFileSize)}`);\r\n return false;\r\n }\r\n\r\n // Check total size\r\n const totalSize = this.getTotalSize() + file.size;\r\n if (totalSize > this.maxTotalSize) {\r\n this.showError(`Total files size exceeded. Maximum: ${this.formatFileSize(this.maxTotalSize)}`);\r\n return false;\r\n }\r\n\r\n // Check file type\r\n if (this.allowedTypes.length > 0 && !this.allowedTypes.includes(file.type)) {\r\n this.showError(`File type \"${file.type}\" for \"${file.name}\" is not supported.`);\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Calculate total size of all files\r\n * @returns {number} Total size in bytes\r\n */\r\n getTotalSize() {\r\n return this.files.reduce((sum, fileData) => sum + fileData.file.size, 0);\r\n }\r\n\r\n /**\r\n * Add a file to the upload queue\r\n * @param {File} file - File to add\r\n * @returns {void}\r\n */\r\n addFile(file) {\r\n const fileWithId = {\r\n id: this.generateFileId(),\r\n file: file\r\n };\r\n\r\n this.files.push(fileWithId);\r\n this.renderFileList();\r\n }\r\n\r\n /**\r\n * Generate a unique file ID\r\n * @returns {string} Unique file identifier\r\n * @private\r\n */\r\n generateFileId() {\r\n return Date.now() + Math.random().toString(36).substr(2, 9);\r\n }\r\n\r\n /**\r\n * Remove a file from the upload queue\r\n * @param {string} fileId - ID of the file to remove\r\n * @returns {void}\r\n */\r\n removeFile(fileId) {\r\n this.files = this.files.filter(f => f.id !== fileId);\r\n this.renderFileList();\r\n this.clearError();\r\n }\r\n\r\n /**\r\n * Render the file list in the UI\r\n * @returns {void}\r\n */\r\n renderFileList() {\r\n if (!this.fileList) return;\r\n\r\n if (this.files.length === 0) {\r\n this.fileList.innerHTML = ksesFilter('
No files attached
');\r\n return;\r\n }\r\n\r\n const fileItems = this.files.map(fileData => this.createFileItem(fileData));\r\n this.fileList.innerHTML = ksesFilter('');\r\n fileItems.forEach(item => this.fileList.appendChild(item));\r\n }\r\n\r\n /**\r\n * Create file item element for display\r\n * @param {object} fileData - File data object\r\n * @param {string} fileData.id - File identifier\r\n * @param {File} fileData.file - File object\r\n * @returns {HTMLDivElement} File item DOM element\r\n */\r\n createFileItem(fileData) {\r\n const { file, id } = fileData;\r\n const fileItem = document.createElement('div');\r\n fileItem.className = 'doboard_task_widget__file-upload__file-item';\r\n\r\n fileItem.innerHTML = ksesFilter(`\r\n
\r\n
\r\n
${this.escapeHtmlHandler(String(file.name))}
\r\n
${this.formatFileSize(file.size)}
\r\n
\r\n
\r\n \r\n `);\r\n\r\n const removeBtn = fileItem.querySelector('.doboard_task_widget__file-upload__remove-btn');\r\n removeBtn.addEventListener('click', () => this.removeFile(id));\r\n\r\n return fileItem;\r\n }\r\n\r\n /**\r\n * Format file size for display\r\n * @param {number} bytes - File size in bytes\r\n * @returns {string} Formatted file size string\r\n */\r\n formatFileSize(bytes) {\r\n if (bytes === 0) return '0 Bytes';\r\n\r\n const k = 1024;\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n\r\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + this.SIZE_UNITS[i];\r\n }\r\n\r\n /**\r\n * Show uploader error message\r\n * @param {string} message - Error message to display\r\n * @returns {void}\r\n */\r\n showError(message) {\r\n if (this.errorMessage) {\r\n this.errorMessage.textContent = message;\r\n this.errorMessage.style.display = 'block';\r\n }\r\n }\r\n\r\n /**\r\n * Clear uploader error message\r\n * @returns {void}\r\n */\r\n clearError() {\r\n if (this.errorMessage) {\r\n this.errorMessage.textContent = '';\r\n this.errorMessage.style.display = 'none';\r\n }\r\n }\r\n\r\n /**\r\n * Check if there are files to send\r\n * @returns {boolean} True if files are present, false otherwise\r\n */\r\n hasFiles() {\r\n return this.files.length > 0;\r\n }\r\n\r\n /**\r\n * Clear all files from upload queue\r\n * @returns {void}\r\n */\r\n clearFiles() {\r\n this.files = [];\r\n this.renderFileList();\r\n }\r\n\r\n /**\r\n * Validate file data structure before upload\r\n * @param {object} fileData - File data object to validate\r\n * @param {string} fileData.sessionId - Session identifier\r\n * @param {object} fileData.params - Additional parameters\r\n * @param {string} fileData.params.accountId - Account identifier\r\n * @param {string} fileData.params.projectToken - Project token\r\n * @param {string} fileData.commentId - Comment identifier\r\n * @param {string} fileData.fileName - File name\r\n * @param {File} fileData.fileBinary - File binary data\r\n * @returns {object} Validated file data\r\n * @throws {Error} When file data validation fails\r\n */\r\n validateFileData(fileData) {\r\n const validations = [\r\n { field: 'sessionId', type: 'string', message: 'No valid session found.' },\r\n { field: 'params.accountId', type: 'string', message: 'No valid account ID found.' },\r\n { field: 'params.projectToken', type: 'string', message: 'No valid project token found.' },\r\n { field: 'commentId', type: 'string', message: 'No valid commentId found.' },\r\n { field: 'fileName', type: 'string', message: 'No valid filename found.' }\r\n ];\r\n\r\n for (const validation of validations) {\r\n const value = this.getNestedValue(fileData, validation.field);\r\n if (!value || typeof value !== validation.type) {\r\n throw new Error(validation.message);\r\n }\r\n }\r\n\r\n if (!fileData.fileBinary || !(fileData.fileBinary instanceof File)) {\r\n throw new Error('No valid file object found.');\r\n }\r\n\r\n return fileData;\r\n }\r\n\r\n /**\r\n * Helper to get nested object values\r\n * @param {object} obj - Object to traverse\r\n * @param {string} path - Dot notation path to value\r\n * @returns {*} Value at the specified path\r\n * @private\r\n */\r\n getNestedValue(obj, path) {\r\n return path.split('.').reduce((current, key) => current?.[key], obj);\r\n }\r\n\r\n /**\r\n * Send single file attachment\r\n * @param {object} fileData - File data for upload\r\n * @returns {Promise} Upload response\r\n */\r\n async sendSingleAttachment(fileData) {\r\n const validatedFileData = await this.validateFileData(fileData);\r\n return await attachmentAddDoboard(validatedFileData);\r\n }\r\n\r\n /**\r\n * Send all attachments for a comment\r\n * @param {object} params - Upload parameters\r\n * @param {string} sessionId - Session identifier\r\n * @param {string} commentId - Comment identifier\r\n * @returns {Promise} Upload results\r\n */\r\n async sendAttachmentsForComment(params, sessionId, commentId) {\r\n /** @type {object} */\r\n const results = {\r\n preparedFilesCount: this.files.length,\r\n sentFilesCount: 0,\r\n fileResults: [],\r\n success: true\r\n };\r\n\r\n for (let i = 0; i < this.files.length; i++) {\r\n const fileData = this.files[i];\r\n /** @type {object} */\r\n const result = {\r\n success: false,\r\n response: null,\r\n error: null\r\n };\r\n\r\n try {\r\n const attachmentData = {\r\n params,\r\n sessionId,\r\n commentId,\r\n fileName: fileData.file.name,\r\n fileBinary: fileData.file,\r\n attachmentOrder: i\r\n };\r\n\r\n const response = await this.sendSingleAttachment(attachmentData);\r\n result.response = response;\r\n result.success = response.status === 200;\r\n\r\n if (result.success) {\r\n results.sentFilesCount++;\r\n }\r\n } catch (error) {\r\n result.error = error.message;\r\n }\r\n\r\n results.fileResults.push(result);\r\n }\r\n\r\n results.success = results.preparedFilesCount === results.sentFilesCount;\r\n this.clearFiles();\r\n\r\n return results;\r\n }\r\n}\r\n\nclass SpotFixTemplatesLoader {\r\n static getTemplateCode(templateName) {\r\n const templateMethod = this[templateName];\r\n\r\n if (typeof templateMethod !== 'function') {\r\n throw new Error(`Template method '${templateName}' not found`);\r\n }\r\n\r\n let template = templateMethod.call(this).trim();\r\n\r\n return template;\r\n }\r\n\r\n static all_issues() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n All spots \r\n
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n
`;\r\n }\r\n\r\n static concrete_issue() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n All {{issuesCounter}}\r\n
\r\n
{{issueTitle}}
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n \r\n \r\n
\r\n
\r\n
Attached files
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static concrete_issue_day_content() {\r\n return `\r\n
\r\n
{{dayContentMonthDay}}
\r\n
{{dayContentMessages}}
\r\n {{statusFixedHtml}}\r\n
\r\n`;\r\n }\r\n\r\n static concrete_issue_messages() {\r\n return `\r\n
\r\n
\r\n {{taskAuthorInitials}}\r\n
\r\n
\r\n
{{commentBody}}
\r\n
{{commentTime}}
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static create_issue() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n Report an issue\r\n
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n Tell us about any issue you’re experiencing on {{currentDomain}}. \r\n You’re also welcome to review spelling, grammar, or ask a question related to this page.\r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n\r\n If you want to receive notifications by email write here you email contacts.\r\n\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n Note about DoBoard register and accepting email notifications about tasks have to be here.\r\n\r\n
\r\n\r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static list_issues() {\r\n return `\r\n
\r\n
\r\n {{taskAuthorInitials}}\r\n
\r\n
\r\n
\r\n
\r\n {{taskTitle}}\r\n
\r\n \"\"\r\n
\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n {{statusFixedHtml}}\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static user_menu() {\r\n return `\r\n
\r\n
\r\n
\r\n
\r\n \"\"\r\n Back\r\n
\r\n
\r\n \"\"\r\n
\r\n
\r\n
\r\n \"\"\r\n {{userName}}\r\n {{email}}\r\n \r\n Sign up or Log in\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \"\"\r\n
\r\n \r\n \r\n Show widget on my screen\r\n \r\n The widget will be visible again if you select any text on the site\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n \"\"\r\n Log out\r\n \r\n
\r\n
\r\n
\r\n
\r\n {{spotfixVersion}}\r\n Powered by\r\n \r\n doBoard\r\n \r\n
\r\n
\r\n
`;\r\n }\r\n\r\n static wrap() {\r\n return `\r\n
\r\n\r\n\r\n
\r\n
`;\r\n }\r\n\r\n static wrap_review() {\r\n return `\r\n`;\r\n }\r\n\r\n static fixedHtml() {\r\n return `

Finished

`;\r\n }\r\n static fixedTaskHtml() {\r\n return `

This issue already fixed

`;\r\n }\r\n\r\n}\r\n\nclass SpotFixSVGLoader {\r\n static loadSVG(svgName) {\r\n const svgMethod = this[svgName];\r\n\r\n if (typeof svgMethod !== 'function') {\r\n throw new Error(`Template method '${svgName}' not found`);\r\n }\r\n\r\n return svgMethod.call(this).trim();\r\n }\r\n\r\n static getAsRawSVG(svgName) {\r\n return this.loadSVG(svgName);\r\n }\r\n\r\n static getAsDataURI(svgName) {\r\n const svg = this.loadSVG(svgName);\r\n return this.svgToDataURI(svg);\r\n }\r\n\r\n static svgToDataURI(svgString) {\r\n const bytes = new TextEncoder().encode(svgString);\r\n const baseBtoa = btoa(String.fromCharCode(...bytes));\r\n return `data:image/svg+xml;base64,${baseBtoa}`;\r\n }\r\n\r\n static chevronBack() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static chevronBackDark() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static buttonCloseScreen() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static buttonSendMessage() {\r\n return `\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n`;\r\n }\r\n\r\n static buttonPaperClip() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static logoDoBoardGreen() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static logoDoBoardWrap() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotPublic() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotPrivate() {\r\n return `\r\n\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotWidgetWrapPencil() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconLinkChain() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconEllipsesMore() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconAvatar() {\r\n return `\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n`;\r\n }\r\n\r\n static iconEye() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconDoor() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconPlus() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconMaximize() {\r\n return `\r\n\r\n\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconMarker() {\r\n return ``;\r\n }\r\n}\r\n\nclass SpotFixSourcesLoader {\r\n\r\n constructor() {\r\n this.loadAll();\r\n }\r\n\r\n getCSSCode() {\r\n // global gulp wrapper var\r\n return spotFixCSS;\r\n }\r\n\r\n loadAll() {\r\n this.loadFonts();\r\n this.loadCSS();\r\n };\r\n\r\n loadFonts() {\r\n const preconnect_first = document.createElement('link');\r\n preconnect_first.rel = 'preconnect';\r\n preconnect_first.href = 'https://fonts.googleapis.com';\r\n document.head.appendChild(preconnect_first);\r\n\r\n const preconnect_second = document.createElement('link');\r\n preconnect_second.rel = 'preconnect';\r\n preconnect_second.href = 'https://fonts.gstatic.com';\r\n preconnect_second.crossOrigin = 'crossorigin';\r\n document.head.appendChild(preconnect_second);\r\n\r\n const fontLink = document.createElement('link');\r\n fontLink.rel = 'stylesheet';\r\n fontLink.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap';\r\n document.head.appendChild(fontLink);\r\n }\r\n\r\n loadCSS() {\r\n const style = document.createElement('style');\r\n style.setAttribute('id', 'spotfix_css');\r\n style.textContent = this.getCSSCode();\r\n document.head.appendChild(style);\r\n }\r\n}\r\n\ndocument.dispatchEvent(new CustomEvent('spotFixLoaded', {\r\n detail: {\r\n timestamp: new Date().toISOString(),\r\n message: 'All scripts loaded successfully'\r\n }\r\n}));\r\n"],"names":["async","deleteDB","db","await","window","indexedDB","databases","closeAndDeleteDatabase","name","catch","error","Promise","resolve","reject","openReq","open","dbName","onsuccess","result","close","deleteReq","deleteDatabase","onerror","event","target","putHandler","item","store","e","user_id","taskId","comment_id","request","put","spotfixIndexedDB","INDEXED_DB_NAME","indexedDBVersion","TABLE_USERS","TABLE_TASKS","TABLE_COMMENTS","LOCAL_DATA_BASE_TABLE","keyPath","init","localStorage","getItem","indexedDBName","getIndexedDBName","onupgradeneeded","forEach","objectStoreNames","contains","createObjectStore","createIndex","needInit","missingStores","filter","length","newVersion","version","upgradeRequest","db2","e2","err","table","data","let","transaction","objectStore","Array","isArray","delete","id","getAll","indexName","value","index","clearPut","clearTable","clear","getTable","deleteTable","console","DOBOARD_API_URL","spotfixApiCall","method","accountId","undefined","Error","key","formData","FormData","hasOwnProperty","append","endpointUrl","URL","response","fetch","body","networkError","message","responseBody","json","parseError","operation_status","errorMessage","operation_message","userConfirmEmailDoboard","emailConfirmationToken","email_confirmation_token","encodeURIComponent","sessionId","session_id","userId","email","accounts","operationStatus","createTaskDoboard","taskDetails","project_token","projectToken","project_id","projectId","taskTitle","comment","taskDescription","meta","taskMeta","task_type","task_id","createTaskCommentDoboard","status","commentId","attachmentAddDoboard","fileData","params","account_id","filename","fileName","file","fileBinary","attachment_order","attachmentOrder","registerUserDoboard","nickname","pageURL","confirmation_url","botDetectorData","JSON","parse","bot_detector_event_token","accountExists","user_email_confirmed","operationMessage","userEmailConfirmed","loginUserDoboard","password","logoutUserDoboard","includes","clearLocalstorageOnLogout","getTasksDoboard","tasks","map","task","taskLastUpdate","updated","taskCreated","created","taskCreatorTaskUser","creator_user_id","taskStatus","storageSaveTasksCount","getTasksCommentsDoboard","comments","commentBody","commentDate","issueTitle","task_name","getUserDoboard","users","userUpdateDoboard","timezone","timestamp","success","getReleaseVersion","tag_name","storageSaveSpotfixVersion","SPOTFIX_VERSION","confirmUserEmail","pendingTaskRaw","setItem","pendingTask","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","removeItem","getTasksFullDetails","currentActiveTaskId","find","getUserDetails","currentUserId","sign","location","href","addTaskComment","commentText","getUserTasks","getAllTasks","formatDate","dateStr","date","time","dateObj","Date","replace","isNaN","getTime","offsetMinutes","getTimezoneOffset","localDateObj","getMonth","getDate","getHours","toString","padStart","getMinutes","getTaskAuthorDetails","taskAuthorAvatarImgSrc","taskAuthorName","element","getIssuesCounterString","onPageSpotsCount","totalSpotsCount","getAvatarSrc","author","avatar","m","getAuthorName","trim","registerUser","userEmail","userName","then","document","querySelector","innerText","ksesFilter","classList","remove","getElementById","focus","userUpdate","showMessageCallback","loginUser","userPassword","Intl","DateTimeFormat","resolvedOptions","timeZone","spotFixSplitUrl","url","u","domain","segments","reversed","host","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","checkLogInOutButtonsVisible","el","style","display","closest","changeSize","container","add","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","iconPlus","iconMaximize","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardGreen","logoDoBoardWrap","iconSpotWidgetWrapPencil","iconMarker","iconSpotPublic","iconSpotPrivate","iconLinkChain","fileUploader","FileUploader","escapeHtml","getParams","urlParams","URLSearchParams","search","emailToken","get","newUrl","storageSetWidgetIsClosed","history","replaceState","title","registrationShowMessage","isWidgetClosed","taskHasSiteOwnerUpdate","storageTasksHasUnreadUpdates","checkIfTasksHasSiteOwnerUpdates","storageSaveTasksUpdateData","storageWidgetCloseIsSet","createWidgetElement","bindWidgetInputsInteractive","script","src","Object","fromEntries","searchParams","entries","bindCreateTaskEvents","submitButton","taskTitleElement","taskDescriptionElement","loginSectionElement","userEmailElement","userNameElement","userPasswordElement","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","config","SpotfixWidgetConfig","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","position","Number","verticalPosition","spotfixVersion","iconEye","iconDoor","chevronBackDark","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","spotFixScrollToNodePath","spotFixGetSelectedData","nodePath","positionWidgetContainer","getTaskCount","widgetElementClasses","currentTarget","spotFixOpenWidget","issuesQuantityOnPage","spotsToBeHighlighted","currentURL","sortedTasks","sort","a","b","aIsHere","i","elTask","taskMetaString","taskData","isFixed","taskFullDetails","avatarData","currentPageURL","taskNodePath","taskPublicStatusImgSrc","taskPublicStatusHint","getAvatarData","getTaskFullDetails","listIssuesTemplateVariables","taskLastMessage","lastMessageText","taskPageUrl","taskFormattedPageUrl","lastMessageTime","sanitizeNodePath","avatarCSSClass","avatarStyle","taskAuthorInitials","initialsClass","classUnread","elementBgCSSClass","statusFixedHtml","storageProvidedTaskHasUnreadUpdates","isSpotHaveToBeHighlighted","spotFixHighlightElements","bindIssuesClick","user","gitHubAppVersion","s","issueTitleElement","currentTaskData","String","origin","issuesCommentsContainer","protocol","contenerClasess","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","commentUserId","commentAuthorAvatarSrc","commentAuthorName","commentData","commentTime","issueMessageClassOwner","daysWrapperHTML","day","messageId","currentDayMessages","dayMessagesWrapperHTML","localeCompare","currentMessageTemplateVariables","dayContentMonthDay","dayContentMessages","textarea","handleTextareaChange","contentContainer","scrollTo","top","scrollHeight","behavior","sendButton","widgetClass","preventDefault","input","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","spotFixShowWidget","querySelectorAll","getAttribute","showOneTask","taskHighlightData","getTaskHighlightData","variables","template","SpotFixTemplatesLoader","getTemplateCode","placeholder","replacement","isPlaceholderInAttribute","imgFilter","replaceAll","escapedPlaceholder","RegExp","test","unsafe","tasksCountLS","tasksCount","taskCountElement","wrapElementWithSpotfixHighlight","newElement","cloneNode","wrapper","insertAdjacentElement","taskIdToSearch","currentTaskSpotData","accordionController","context","handleScroll","bind","handleResize","messageText","titleSpan","messageDiv","messageWrap","color","widget","widgetCreateIssue","widgetConcreteIssue","scrollY","viewportHeight","innerHeight","selectionAbsoluteTop","getBoundingClientRect","widgetHeight","offsetHeight","bottom","scrollTimeout","resizeTimeout","str","spotFixCSS","spotFixShowDelayTimeout","SPOTFIX_DEBUG","SPOTFIX_SHOW_DELAY","spotFixInit","SpotFixSourcesLoader","loadBotDetector","head","spotFixIsInsideWidget","node","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","containerClassesToShow","containers","tasksDetails","lastComment","dt","avatarSrc","authorName","authorDetails","charAt","toUpperCase","isAnyTaskUpdated","updatedtasksIDS","currentStateOfTask","issuerId","storageCheckTaskUpdate","updatedTaskIDs","lastMessage","updatedTaskId","updatedTaskData","storageAddUnreadUpdateForTaskID","isSelectionCorrect","html","options","allowedTags","strong","em","ul","ol","li","p","br","span","blockquote","pre","div","img","label","button","details","summary","allowedAttrs","doc","DOMParser","parseFromString","childNodes","clean","tag","tagName","toLowerCase","link","alt","parentNode","insertBefore","textContent","attributes","attr","attrName","startsWith","readyState","sel","isWrapReviewWidgetExists","focusNode","anchorNode","SPOTFIX_SELECTION_TYPE_TEXT","SPOTFIX_SELECTION_TYPE_IMG","SPOTFIX_SELECTION_TYPE_ELEMENT","spotFixGetSelectionType","range","getRangeAt","commonAncestor","commonAncestorContainer","spotFixGetSelectedImage","startContainer","endContainer","hasTextContent","isTextNode","TEXT_NODE","isCollapsed","collapsed","rangeCount","selectionType","startSelectPosition","endSelectPosition","commonNode","commonNodeElement","startOffset","endOffset","spotFixCalculateNodePath","imgElement","selectedImage","from","children","indexOf","imageUrl","widgetInstance","elementsMap","Map","spot","spotFixIsValidNodePath","spotFixRetrieveNodeFromPath","has","set","spots","spotFixHighlightImageElement","spotFixHighlightNestedElement","spotFixHighlightTextInElement","tooltipTitleText","spotfixHighlightOpen","text","spotSelectedText","markers","startPos","parseInt","endPos","slice","marker","insertText","idClass","cls","path","scrollIntoView","block","spans","affectedParents","Set","elementSelectionClassName","parent","tooltip","firstChild","removeChild","normalize","imageSelectionClassName","every","isInteger","imgNode","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","spotFixIsElementInRange","FILTER_ACCEPT","FILTER_REJECT","nextNode","startElement","spotFixGetElementFromNode","endElement","spotFixIsElementPartiallySelected","spotFixFindNearbyElements","elementRange","createRange","selectNode","compareBoundaryPoints","Range","START_TO_START","END_TO_END","elementRect","rangeRect","right","left","elements","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","escapeHtmlHandler","files","maxFileSize","maxTotalSize","maxFiles","allowedTypes","SIZE_UNITS","initializeElements","bindFilesInputChange","fileInput","fileList","uploaderWrapper","warn","handleFileInputChange","click","clearError","selectedFiles","validateFile","addFile","size","formatFileSize","getTotalSize","reduce","sum","fileWithId","generateFileId","renderFileList","now","Math","random","substr","removeFile","fileId","f","fileItems","createFileItem","fileItem","bytes","floor","parseFloat","pow","toFixed","clearFiles","validateFileData","validation","field","getNestedValue","File","obj","current","sendSingleAttachment","validatedFileData","results","preparedFilesCount","sentFilesCount","fileResults","attachmentData","templateMethod","call","all_issues","concrete_issue","concrete_issue_day_content","concrete_issue_messages","create_issue","list_issues","user_menu","wrap","wrap_review","fixedHtml","fixedTaskHtml","loadSVG","svgName","svgMethod","getAsRawSVG","svg","svgToDataURI","svgString","TextEncoder","encode","btoa","fromCharCode","iconAvatar","loadAll","getCSSCode","loadFonts","loadCSS","preconnect_first","preconnect_second","rel","fontLink","crossOrigin","setAttribute","dispatchEvent","CustomEvent","detail","toISOString"],"mappings":"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"} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 4a003bc..4e62d25 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,6 +14,7 @@ let browserSync = require('browser-sync').create(); function bundle_src_js() { const cssStream = processCSS(); const jsStream = gulp.src([ + 'js/src/localDB.js', 'js/src/api.js', 'js/src/constants.js', 'js/src/handlers.js', @@ -54,7 +55,7 @@ function processCSS() { const {deleteSync} = await import('del'); deleteSync('temp'); }) - ; + ; } gulp.task('compress-js', gulp.series(bundle_src_js, minify_js)); diff --git a/js/src/api.js b/js/src/api.js index ac60332..46fbd25 100644 --- a/js/src/api.js +++ b/js/src/api.js @@ -210,7 +210,9 @@ const logoutUserDoboard = async (projectToken, accountId) => { } const result = await spotfixApiCall(data, 'user_unauthorize', accountId); + if (result.operation_status === 'SUCCESS') { + await deleteDB(); clearLocalstorageOnLogout(); } } @@ -230,15 +232,19 @@ const getTasksDoboard = async (projectToken, sessionId, accountId, projectId, us const tasks = result.tasks.map(task => ({ taskId: task.task_id, taskTitle: task.name, + userId: task.user_id, taskLastUpdate: task.updated, taskCreated: task.created, taskCreatorTaskUser: task.creator_user_id, taskMeta: task.meta, taskStatus: task.status, })); - + if (data.task_id) { + await spotfixIndexedDB.put(TABLE_TASKS, tasks); + } else { + await spotfixIndexedDB.clearPut(TABLE_TASKS, tasks); + } storageSaveTasksCount(tasks); - return tasks; } @@ -250,7 +256,7 @@ const getTasksCommentsDoboard = async (sessionId, accountId, projectToken, statu status: status } const result = await spotfixApiCall(data, 'comment_get', accountId); - return result.comments.map(comment => ({ + const comments = result.comments.map(comment => ({ taskId: comment.task_id, commentId: comment.comment_id, userId: comment.user_id, @@ -259,6 +265,12 @@ const getTasksCommentsDoboard = async (sessionId, accountId, projectToken, statu status: comment.status, issueTitle: comment.task_name, })); + if (data.comment_id) { + await spotfixIndexedDB.put(TABLE_COMMENTS, comments); + } else { + await spotfixIndexedDB.clearPut(TABLE_COMMENTS, comments); + } + return comments; }; const getUserDoboard = async (sessionId, projectToken, accountId, userId) => { @@ -269,6 +281,11 @@ const getUserDoboard = async (sessionId, projectToken, accountId, userId) => { if (userId) data.user_id = userId; const result = await spotfixApiCall(data, 'user_get', accountId); + if (data.user_id) { + await spotfixIndexedDB.put(TABLE_USERS, result.users); + } else { + await spotfixIndexedDB.clearPut(TABLE_USERS, result.users); + } return result.users; // @ToDo Need to handle these two different answers? diff --git a/js/src/handlers.js b/js/src/handlers.js index 8fa664d..4f41bc1 100644 --- a/js/src/handlers.js +++ b/js/src/handlers.js @@ -3,6 +3,7 @@ async function confirmUserEmail(emailConfirmationToken, params) { // Save session data to LS localStorage.setItem('spotfix_email', result.email); localStorage.setItem('spotfix_session_id', result.sessionId); + await spotfixIndexedDB.init(); localStorage.setItem('spotfix_user_id', result.userId); // Get pending task from LS @@ -39,8 +40,10 @@ async function confirmUserEmail(emailConfirmationToken, params) { async function getTasksFullDetails(params, tasks, currentActiveTaskId) { if (tasks.length > 0) { const sessionId = localStorage.getItem('spotfix_session_id'); - const comments = await getTasksCommentsDoboard(sessionId, params.accountId, params.projectToken); - const users = await getUserDoboard(sessionId, params.projectToken, params.accountId); + await getTasksCommentsDoboard(sessionId, params.accountId, params.projectToken); + const comments = await spotfixIndexedDB.getAll(TABLE_COMMENTS); + await getUserDoboard(sessionId, params.projectToken, params.accountId); + const users = await spotfixIndexedDB.getAll(TABLE_USERS); const foundTask = tasks.find(item => +item.taskId === +currentActiveTaskId); return { @@ -55,7 +58,8 @@ async function getUserDetails(params) { const sessionId = localStorage.getItem('spotfix_session_id'); const currentUserId = localStorage.getItem('spotfix_user_id'); if(currentUserId) { - const users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); + await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); + const users = await spotfixIndexedDB.getAll(TABLE_USERS); return users[0] || {}; } } @@ -83,14 +87,15 @@ async function addTaskComment(params, taskId, commentText) { return await createTaskCommentDoboard(params.accountId, sessionId, taskId, commentText, params.projectToken); } -function getUserTasks(params) { +async function getUserTasks(params) { if (!localStorage.getItem('spotfix_session_id')) { return {}; } const projectToken = params.projectToken; const sessionId = localStorage.getItem('spotfix_session_id'); const userId = localStorage.getItem('spotfix_user_id'); - return getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId, userId); + await getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId, userId); + return await spotfixIndexedDB.getAll(TABLE_TASKS, 'userId', userId); } async function getAllTasks(params) { @@ -99,8 +104,8 @@ async function getAllTasks(params) { } const projectToken = params.projectToken; const sessionId = localStorage.getItem('spotfix_session_id'); - const tasksData = await getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId); - + await getTasksDoboard(projectToken, sessionId, params.accountId, params.projectId); + const tasksData = await spotfixIndexedDB.getAll(TABLE_TASKS); // Get only tasks with metadata const filteredTaskData = tasksData.filter(task => { return task.taskMeta; @@ -204,6 +209,7 @@ function registerUser(taskDetails) { document.getElementById("doboard_task_widget-user_password").focus(); } else if (response.sessionId) { localStorage.setItem('spotfix_session_id', response.sessionId); + spotfixIndexedDB.init(); localStorage.setItem('spotfix_user_id', response.userId); localStorage.setItem('spotfix_email', response.email); userUpdate(projectToken, accountId); @@ -233,6 +239,7 @@ function loginUser(taskDetails) { .then(response => { if (response.sessionId) { localStorage.setItem('spotfix_session_id', response.sessionId); + spotfixIndexedDB.init(); localStorage.setItem('spotfix_user_id', response.userId); localStorage.setItem('spotfix_email', userEmail); } else if (response.operationStatus === 'SUCCESS' && response.operationMessage && response.operationMessage.length > 0) { diff --git a/js/src/localDB.js b/js/src/localDB.js new file mode 100644 index 0000000..d52a993 --- /dev/null +++ b/js/src/localDB.js @@ -0,0 +1,266 @@ +async function deleteDB () { + try { + const dbs = await window.indexedDB.databases(); + for (const db of dbs) { + closeAndDeleteDatabase(db.name).catch(() => {}); + } + } catch (error) {} +} + +const closeAndDeleteDatabase = (dbName) => { + return new Promise((resolve, reject) => { + const openReq = indexedDB.open(dbName); + + openReq.onsuccess = () => { + const db = openReq.result; + db.close(); + const deleteReq = indexedDB.deleteDatabase(dbName); + deleteReq.onsuccess = () => { + resolve(); + }; + deleteReq.onerror = (event) => { + reject(event.target.error); + }; + }; + + openReq.onerror = () => { + const deleteReq = indexedDB.deleteDatabase(dbName); + deleteReq.onsuccess = () => { + resolve(); + }; + deleteReq.onerror = (event) => { + reject(event.target.error); + }; + }; + }); +}; + +function putHandler(item, store, e) { + if (item?.user_id || item?.taskId || item?.comment_id) { + const request = store?.put(item); + if (request) { + request.onsuccess = function() { + e.target.result.close(); + }; + request.onerror = function() { + e.target.result.close(); + spotfixIndexedDB.error(request, e); + }; + } + } +} + +const INDEXED_DB_NAME = 'spotfix-localDB'; +const indexedDBVersion = 1; + +const TABLE_USERS = 'users'; +const TABLE_TASKS = 'tasks'; +const TABLE_COMMENTS = 'comments'; + +const LOCAL_DATA_BASE_TABLE = [ + {name: TABLE_USERS, keyPath: 'user_id'}, + {name: TABLE_TASKS, keyPath: 'taskId'}, + {name: TABLE_COMMENTS, keyPath: 'commentId'}, +]; + +const spotfixIndexedDB = { + init: async () => { + return new Promise((resolve, reject) => { + if (!localStorage.getItem('spotfix_session_id')) { + resolve({ needInit: false }); + return; + } + + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const request = window.indexedDB.open(indexedDBName, indexedDBVersion); + + request.onupgradeneeded = (e) => { + const db = e.target.result; + LOCAL_DATA_BASE_TABLE.forEach((item) => { + if (!db.objectStoreNames.contains(item.name)) { + const store = db.createObjectStore(item.name, { keyPath: item.keyPath }); + if (item.name === TABLE_COMMENTS) store.createIndex('taskId', 'taskId'); + if (item.name === TABLE_TASKS) store.createIndex('userId', 'userId'); + } + }); + resolve({ needInit: true }); + }; + + request.onsuccess = (e) => { + const db = e.target.result; + + const missingStores = LOCAL_DATA_BASE_TABLE.filter(item => !db.objectStoreNames.contains(item.name)); + if (missingStores.length === 0) { + db.close(); + resolve({ needInit: false }); + } else { + const newVersion = db.version + 1; + db.close(); + const upgradeRequest = window.indexedDB.open(indexedDBName, newVersion); + upgradeRequest.onupgradeneeded = (e2) => { + const db2 = e2.target.result; + missingStores.forEach(item => { + const store = db2.createObjectStore(item.name, { keyPath: item.keyPath }); + if (item.name === TABLE_COMMENTS) store.createIndex('taskId', 'taskId'); + if (item.name === TABLE_TASKS) store.createIndex('userId', 'userId'); + }); + }; + upgradeRequest.onsuccess = () => resolve({ needInit: true }); + upgradeRequest.onerror = (err) => reject(err); + } + }; + + request.onerror = (err) => reject(err); + }); + }, + put: async (table, data) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion); + + indexedDB.onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table, 'readwrite'); + } catch (e) {} + const store = transaction?.objectStore(table); + if (Array.isArray(data)) { + data.forEach((item) => { + putHandler(item, store, e); + }); + } else { + putHandler(data, store, e); + } + }; + }, + + delete: async (table, id) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion); + + indexedDB.onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table, 'readwrite'); + } catch (e) {} + const store = transaction?.objectStore(table); + store.delete(id); + }; + }, + + getAll: async (table, indexName, value) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion); + + return await new Promise( + (resolve, reject) => { + indexedDB.onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table, 'readwrite'); + } catch (e) {} + const store = transaction?.objectStore(table); + if (store) { + if (indexName && value) { + let index = store.index(indexName); + let request = index.getAll(value); + request.onsuccess = function() { + resolve(request.result); + }; + // eslint-disable-next-line prefer-promise-reject-errors + request.onerror = () => reject('Err'); + } else { + let request = store.getAll(); + request.onsuccess = function() { + resolve(request.result); + }; + // eslint-disable-next-line prefer-promise-reject-errors + request.onerror = () => reject('Err'); + } + } + }; + // eslint-disable-next-line prefer-promise-reject-errors + indexedDB.onerror = () => reject('Err'); + }, + ); + }, + + clearPut: async (table, data) => { + await spotfixIndexedDB.clearTable(table, data); + spotfixIndexedDB.put(table, data); + }, + + clearTable: async (table) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + const indexedDB = await window.indexedDB.open(indexedDBName, indexedDBVersion); + + indexedDB.onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table, 'readwrite'); + } catch (e) {} + const store = transaction?.objectStore(table); + const request = store?.clear(); + if (request) { + request.onsuccess = function() { + e.target.result.close(); + }; + request.onerror = function() { + e.target.result.close(); + spotfixIndexedDB.error(request, e); + }; + } + }; + }, + + getTable: async (table) => { + return new Promise((resolve) => { + if (!localStorage.getItem('spotfix_session_id')) { + resolve(); + } else { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + window.indexedDB.open(indexedDBName, indexedDBVersion).onsuccess = function(e) { + let transaction; + try { + transaction = e.target.result.transaction(table); + } catch (e) { + } + const store = transaction?.objectStore(table); + const request = store?.getAll(); + if (request) { + request.onsuccess = (event) => { + e.target.result.close(); + resolve(event.target.result); + }; + request.onerror = function() { + e.target.result.close(); + spotfixIndexedDB.error(request, e); + }; + } + }; + } + }); + }, + + deleteTable: async (table, index) => { + const indexedDBName = spotfixIndexedDB.getIndexedDBName(); + return window.indexedDB.open(indexedDBName, indexedDBVersion).onsuccess = function(e) { + const transaction = e.target.result.transaction(table, 'readwrite'); + const store = transaction?.objectStore(table); + const request = store.delete(index); + request.onsuccess = () => { + e.target.result.close(); + }; + request.onerror = function() { + e.target.result.close(); + spotfixIndexedDB.error(request, e); + }; + }; + }, + + getIndexedDBName: () => { + return `${INDEXED_DB_NAME}_${localStorage.getItem('spotfix_session_id')}`; + }, + error: (request, error) => { + console.error('IndexedDB', request, error); + }, +}; diff --git a/js/src/main.js b/js/src/main.js index a1d2233..f0e026b 100644 --- a/js/src/main.js +++ b/js/src/main.js @@ -9,6 +9,7 @@ if( document.readyState !== 'loading' ) { } function spotFixInit() { + spotfixIndexedDB.init(); new SpotFixSourcesLoader(); new CleanTalkWidgetDoboard({}, 'wrap'); loadBotDetector() diff --git a/js/src/widget.js b/js/src/widget.js index d70f905..4b79102 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -882,7 +882,8 @@ class CleanTalkWidgetDoboard { let tasksCount; if(tasksCountLS !== 0 && !tasksCountLS){ - const tasks = await getTasksDoboard(projectToken, sessionId, this.params.accountId, this.params.projectId); + await getTasksDoboard(projectToken, sessionId, this.params.accountId, this.params.projectId); + const tasks = await spotfixIndexedDB.getAll(TABLE_TASKS); const filteredTasks = tasks.filter(task => { return task.taskMeta; });