diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 7c3c2c0..f8803b4 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -3518,7 +3518,7 @@ class SpotFixTemplatesLoader { -
+
diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 32e44b0..3e7371c 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -236,7 +236,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
-
+
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 2f6b5fa..ae43645 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 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 (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 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\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', response.email);\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 const position = {\r\n compact: '0vh',\r\n short: '20vh',\r\n regular: '45vh',\r\n tall: '60vh',\r\n extra: '85vh',\r\n };\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: position[config?.verticalPosition] || position.compact, ...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {position: position[config?.verticalPosition] || position.compact, ...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 versionFromLS = localStorage.getItem('spotfix_app_version');\r\n templateVariables = {\r\n spotfixVersion: versionFromLS ? 'Spotfix version ' + versionFromLS + '.' : '',\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;\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.accountId);\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}\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\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 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 * 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","accountExists","user_email_confirmed","operationMessage","userEmailConfirmed","loginUserDoboard","password","logoutUserDoboard","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","confirmUserEmail","pendingTaskRaw","setItem","pendingTask","JSON","parse","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","includes","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","value","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","position","compact","short","regular","tall","extra","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","verticalPosition","versionFromLS","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","version","s","issueTitleElement","currentTaskData","String","origin","issuesCommentsContainer","protocol","contenerClasess","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","Number","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","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","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","spotFixCSS","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","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","head","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":["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 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 (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 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\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', response.email);\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 const position = {\r\n compact: '0vh',\r\n short: '20vh',\r\n regular: '45vh',\r\n tall: '60vh',\r\n extra: '85vh',\r\n };\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: position[config?.verticalPosition] || position.compact, ...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {position: position[config?.verticalPosition] || position.compact, ...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 versionFromLS = localStorage.getItem('spotfix_app_version');\r\n templateVariables = {\r\n spotfixVersion: versionFromLS ? 'Spotfix version ' + versionFromLS + '.' : '',\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;\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.accountId);\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}\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\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 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 * 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","accountExists","user_email_confirmed","operationMessage","userEmailConfirmed","loginUserDoboard","password","logoutUserDoboard","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","confirmUserEmail","pendingTaskRaw","setItem","pendingTask","JSON","parse","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","includes","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","value","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","position","compact","short","regular","tall","extra","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","verticalPosition","versionFromLS","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","version","s","issueTitleElement","currentTaskData","String","origin","issuesCommentsContainer","protocol","contenerClasess","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","Number","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","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","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","spotFixCSS","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","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","head","fontLink","crossOrigin","setAttribute","dispatchEvent","CustomEvent","detail","toISOString"],"mappings":"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"} \ No newline at end of file diff --git a/js/src/loaders/SpotFixTemplatesLoader.js b/js/src/loaders/SpotFixTemplatesLoader.js index 575845e..d5f9079 100644 --- a/js/src/loaders/SpotFixTemplatesLoader.js +++ b/js/src/loaders/SpotFixTemplatesLoader.js @@ -260,7 +260,7 @@ class SpotFixTemplatesLoader { -
+