From ba19a01403c45303ada7136a3aef482c5533c4eb Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Thu, 18 Dec 2025 00:12:07 +0400 Subject: [PATCH 01/20] Upd. Added user menu. --- dist/doboard-widget-bundle.js | 233 +++++++++++++++++++++-- dist/doboard-widget-bundle.min.js | 116 ++++++++++- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/api.js | 21 +- js/src/handlers.js | 16 ++ js/src/loaders/SpotFixSVGLoader.js | 54 ++++++ js/src/loaders/SpotFixTemplatesLoader.js | 82 +++++++- js/src/widget.js | 58 +++++- styles/doboard-widget.css | 96 +++++++++- 9 files changed, 636 insertions(+), 42 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 341c86c..f013fd3 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -230,11 +230,13 @@ const getTasksCommentsDoboard = async (sessionId, accountId, projectToken, statu })); }; -const getUserDoboard = async (sessionId, projectToken, accountId) => { +const getUserDoboard = async (sessionId, projectToken, accountId, userId) => { const data = { session_id: sessionId, project_token: projectToken, } + if (userId) data.user_id = userId; + const result = await spotfixApiCall(data, 'user_get', accountId); return result.users; @@ -278,6 +280,23 @@ const userUpdateDoboard = async (projectToken, accountId, sessionId, userId, tim }; } +const getReleaseVersion = async () => { + try { + const res = await fetch('https://api.github.com/repos/CleanTalk/SpotFix/releases'); + const data = await res.json(); + + if (data.length > 0 && data[0].tag_name) { + localStorage.setItem('spotfix_app_version', data[0].tag_name); + return data[0].tag_name; + } + + return null; + } catch (err) { + return null; + } +}; + + async function confirmUserEmail(emailConfirmationToken, params) { const result = await userConfirmEmailDoboard(emailConfirmationToken); // Save session data to LS @@ -331,6 +350,13 @@ async function getTasksFullDetails(params, tasks, currentActiveTaskId) { } } +async function getUserDetails(params) { + const sessionId = localStorage.getItem('spotfix_session_id'); + const currentUserId = localStorage.getItem('spotfix_user_id'); + const users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); + return users[0] || {}; +} + async function handleCreateTask(sessionId, taskDetails) { try { const result = await createTaskDoboard(sessionId, taskDetails); @@ -547,6 +573,15 @@ function spotFixSplitUrl(url) { } +function setToggleStatus(rootElement){ + const clickHandler = () => { + localStorage.setItem('spotfix_widget_is_closed', '1'); + rootElement.hide(); + }; + const toggle = document.getElementById('widget_visibility'); + toggle.checked = true; + toggle.addEventListener('click', clickHandler); +} /** * Widget class to create a task widget @@ -571,6 +606,7 @@ class CleanTalkWidgetDoboard { this.init(type); this.srcVariables = { buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), + iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'), buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'), buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'), @@ -828,10 +864,12 @@ class CleanTalkWidgetDoboard { switch (type) { case 'create_issue': templateName = 'create_issue'; + this.type_name = templateName; templateVariables = { selectedText: this.selectedText, currentDomain: document.location.hostname || '', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), + iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), ...this.srcVariables }; storageGetUserIsDefined() && storageSetWidgetIsClosed(false); @@ -849,10 +887,26 @@ class CleanTalkWidgetDoboard { break; case 'all_issues': templateName = 'all_issues'; + this.type_name = templateName; templateVariables = {...this.srcVariables}; break; + case 'user_menu': + templateName = 'user_menu'; + const versionFromLS = localStorage.getItem('spotfix_app_version'); + templateVariables = { + spotfixVersion: versionFromLS ? 'Spotfix version ' + versionFromLS + '.' : '', + avatar: SpotFixSVGLoader.getAsDataURI('iconAvatar'), + iconEye: SpotFixSVGLoader.getAsDataURI('iconEye'), + iconDoor: SpotFixSVGLoader.getAsDataURI('iconDoor'), + chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'), + buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'), + userName: '', + email: '', + ...this.srcVariables}; + break; case 'concrete_issue': templateName = 'concrete_issue'; + this.type_name = templateName; // Update the number of tasks this.savedIssuesQuantityAll = Array.isArray(this.allTasksData) ? this.allTasksData.length : 0; // Calculate the number of issues on the current page @@ -1023,7 +1077,28 @@ class CleanTalkWidgetDoboard { this.bindIssuesClick(); hideContainersSpinner(false); break; + case 'user_menu': + + setToggleStatus(this); + const user = await getUserDetails(this.params); + const gitHubAppVersion = await getReleaseVersion(); + let spotfixVersion = ''; + const version = localStorage.getItem('spotfix_app_version') || gitHubAppVersion; + spotfixVersion = version ? `Spotfix version ${version}.` : ''; + + templateVariables.spotfixVersion = spotfixVersion || ''; + if(user){ + templateVariables.userName = user.name; + templateVariables.email = user.email; + if(user?.avatar?.s) templateVariables.avatar = user?.avatar?.s; + } + + widgetContainer.innerHTML = this.loadTemplate('user_menu', templateVariables); + document.body.appendChild(widgetContainer); + setToggleStatus(this); + + break; case 'concrete_issue': tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId); @@ -1206,16 +1281,24 @@ class CleanTalkWidgetDoboard { this.fileUploader.bindPaperClipAction(paperclipController); } - document.querySelector('.doboard_task_widget-close_btn')?.addEventListener('click', () => { + document.querySelector('.doboard_task_widget-close_btn')?.addEventListener('click', (e) => { this.hide(); }) || ''; - document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => { - const widget = document.querySelector('.doboard_task_widget-wrap'); - widget.classList.add('hidden'); - storageSetWidgetIsClosed(true); + document.querySelector('#openUserMenuButton')?.addEventListener('click', () => { + this.createWidgetElement('user_menu') + }) || ''; + + document.querySelector('#spotfix_back_button')?.addEventListener('click', () => { + this.createWidgetElement(this.type_name) }) || ''; + // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => { + // const widget = document.querySelector('.doboard_task_widget-wrap'); + // widget.classList.add('hidden'); + // storageSetWidgetIsClosed(true); + // }) || ''; + return widgetContainer; } @@ -2492,7 +2575,7 @@ function spotFixRetrieveNodeFromPath(path) { return node; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:360px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;justify-content:space-between;align-items:center;color:#FFF}.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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count:hover{background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHZpZXdCb3g9IjAgMCAyMiAyMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxmb3JlaWduT2JqZWN0IHg9Ii00IiB5PSItNCIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIj48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iYmFja2Ryb3AtZmlsdGVyOmJsdXIoMnB4KTtjbGlwLXBhdGg6dXJsKCNiZ2JsdXJfMF8xODk4OV8yODI2X2NsaXBfcGF0aCk7aGVpZ2h0OjEwMCU7d2lkdGg6MTAwJSI+PC9kaXY+PC9mb3JlaWduT2JqZWN0PjxwYXRoIGRhdGEtZmlnbWEtYmctYmx1ci1yYWRpdXM9IjQiIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjciLz4KICAgIDxwYXRoIGQ9Ik0xNiA2TDYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxwYXRoIGQ9Ik02IDZMMTYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxkZWZzPgogICAgICAgIDxjbGlwUGF0aCBpZD0iYmdibHVyXzBfMTg5ODlfMjgyNl9jbGlwX3BhdGgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgNCkiPjxwYXRoIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIi8+CiAgICAgICAgPC9jbGlwUGF0aD48L2RlZnM+Cjwvc3ZnPg==) center no-repeat;cursor:pointer;overflow:hidden;font-size:0}#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:40px}.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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`; +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} @@ -3084,7 +3167,12 @@ class SpotFixTemplatesLoader { All spots - +
+ + + + +
@@ -3110,7 +3198,12 @@ class SpotFixTemplatesLoader { All {{issuesCounter}}
{{issueTitle}}
- +
+ + + + +
@@ -3179,14 +3272,19 @@ class SpotFixTemplatesLoader { Report an issue
- +
+ + + + +
- If you found issue with {{currentDomain}} page, you are in right place. Please use this form to tell us about the issue you’re experiencing. - doboard.com + Tell us about any issue you’re experiencing on {{currentDomain}}. + You’re also welcome to review spelling, grammar, or ask a question related to this page.
@@ -3269,6 +3367,63 @@ class SpotFixTemplatesLoader { `; } + static user_menu() { + return ` +
+
+
+
+ + Back +
+
+ +
+
+
+ + {{userName}} + {{email}} +
+
+
+
+
+
+ +
+ + + Show widget on my screen + + The widget will be visible again if you select any text on the site + + +
+
+
+ +
+ Log out +
+
+
+
+
+ {{spotfixVersion}} + Powered by + + doboard.com + +
+
+
`; + } + static wrap() { return `
@@ -3328,6 +3483,13 @@ class SpotFixSVGLoader { `; } + static chevronBackDark() { + return ` + + +`; + } + static buttonCloseScreen() { return ` @@ -3336,6 +3498,14 @@ class SpotFixSVGLoader { `; } + static buttonCloseScreenDark() { + return ` + + + +`; + } + static buttonSendMessage() { return ` @@ -3403,6 +3573,45 @@ class SpotFixSVGLoader { `; } + + static iconEllipsesMore() { + return ` + + + +`; + } + + static iconAvatar() { + return ` + + + + + + + + +`; + } + + static iconEye() { + return ` + + + +`; + } + + static iconDoor() { + return ` + + + +`; + } } class SpotFixSourcesLoader { diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index c759285..b381545 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a)=>{e={session_id:e,project_token:t};return(await spotfixApiCall(e,"user_get",a)).users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}};async function confirmUserEmail(e,t){var e=await userConfirmEmailDoboard(e),a=(localStorage.setItem("spotfix_email",e.email),localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.getItem("spotfix_pending_task"));if(!a)throw new Error("No pending task data");let i;try{i=JSON.parse(a)}catch(e){throw new Error("Invalid pending task data")}a={taskTitle:i.selectedText||"New Task",taskDescription:i.description||"",selectedData:i,projectToken:t.projectToken,projectId:t.projectId,accountId:t.accountId,taskMeta:JSON.stringify(i)},t=await handleCreateTask(e.sessionId,a);return localStorage.removeItem("spotfix_pending_task"),t}async function getTasksFullDetails(e,t,a){var i;if(0+e.taskId==+a)?.taskStatus}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",l={...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,_=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);p=document.querySelector(".doboard_task_widget-issue-title");p&&(p.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;c=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(c&&c.taskMeta)try{i=JSON.parse(c.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var g=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),C){var D=C[S];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:T,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function E(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let a=this;e&&e.addEventListener("click",function(e,t=a){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",()=>{this.hide()}),document.querySelector("#doboard_task_widget-task_count")?.addEventListener("click",()=>{document.querySelector(".doboard_task_widget-wrap").classList.add("hidden"),storageSetWidgetIsClosed(!0)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId.toString()===t.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(e){var t=document.getElementById("widget_visibility");t.checked=!0,t.addEventListener("click",()=>{localStorage.setItem("spotfix_widget_is_closed","1"),e.hide()})}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,_=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this);p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name,l.email=p.email,p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this);break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:T,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId.toString()===t.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
@@ -19,7 +19,12 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) All spots
- +
+ + + + +
@@ -41,7 +46,12 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) All {{issuesCounter}}
{{issueTitle}}
- +
+ + + + +
@@ -98,14 +108,19 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) Report an issue
- +
+ + + + +
- If you found issue with {{currentDomain}} page, you are in right place. Please use this form to tell us about the issue you’re experiencing. - doboard.com + Tell us about any issue you’re experiencing on {{currentDomain}}. + You’re also welcome to review spelling, grammar, or ask a question related to this page.
@@ -181,7 +196,60 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
-`}static wrap(){return` +`}static user_menu(){return` +
+
+
+
+ + Back +
+
+ +
+
+
+ + {{userName}} + {{email}} +
+
+
+
+
+
+ +
+ + + Show widget on my screen + + The widget will be visible again if you select any text on the site + + +
+
+
+ +
+ Log out +
+
+
+
+
+ {{spotfixVersion}} + Powered by + + doboard.com + +
+
+
`}static wrap(){return`
@@ -193,10 +261,17 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) `}static fixedHtml(){return'

Finished

'}static fixedTaskHtml(){return'

This issue already fixed

'}}class SpotFixSVGLoader{static loadSVG(e){var t=this[e];if("function"!=typeof t)throw new Error(`Template method '${e}' not found`);return t.call(this).trim()}static getAsRawSVG(e){return this.loadSVG(e)}static getAsDataURI(e){e=this.loadSVG(e);return this.svgToDataURI(e)}static svgToDataURI(e){e=(new TextEncoder).encode(e);return"data:image/svg+xml;base64,"+btoa(String.fromCharCode(...e))}static chevronBack(){return` +`}static chevronBackDark(){return` + + `}static buttonCloseScreen(){return` +`}static buttonCloseScreenDark(){return` + + + `}static buttonSendMessage(){return` @@ -233,5 +308,28 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) `}static iconLinkChain(){return` -`}}class SpotFixSourcesLoader{constructor(){this.loadAll()}getCSSCode(){return spotFixCSS}loadAll(){this.loadFonts(),this.loadCSS()}loadFonts(){var e=document.createElement("link"),e=(e.rel="preconnect",e.href="https://fonts.googleapis.com",document.head.appendChild(e),document.createElement("link")),e=(e.rel="preconnect",e.href="https://fonts.gstatic.com",e.crossOrigin="crossorigin",document.head.appendChild(e),document.createElement("link"));e.rel="stylesheet",e.href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",document.head.appendChild(e)}loadCSS(){var e=document.createElement("style");e.setAttribute("id","spotfix_css"),e.textContent=this.getCSSCode(),document.head.appendChild(e)}}document.dispatchEvent(new CustomEvent("spotFixLoaded",{detail:{timestamp:(new Date).toISOString(),message:"All scripts loaded successfully"}})); +`}static iconEllipsesMore(){return` + + + +`}static iconAvatar(){return` + + + + + + + + +`}static iconEye(){return` + + + +`}static iconDoor(){return` + + + +`}}class SpotFixSourcesLoader{constructor(){this.loadAll()}getCSSCode(){return spotFixCSS}loadAll(){this.loadFonts(),this.loadCSS()}loadFonts(){var e=document.createElement("link"),e=(e.rel="preconnect",e.href="https://fonts.googleapis.com",document.head.appendChild(e),document.createElement("link")),e=(e.rel="preconnect",e.href="https://fonts.gstatic.com",e.crossOrigin="crossorigin",document.head.appendChild(e),document.createElement("link"));e.rel="stylesheet",e.href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",document.head.appendChild(e)}loadCSS(){var e=document.createElement("style");e.setAttribute("id","spotfix_css"),e.textContent=this.getCSSCode(),document.head.appendChild(e)}}document.dispatchEvent(new CustomEvent("spotFixLoaded",{detail:{timestamp:(new Date).toISOString(),message:"All scripts loaded successfully"}})); //# sourceMappingURL=doboard-widget-bundle.min.js.map diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index d152ef0..0841bf3 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 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) => {\r\n const data = {\r\n session_id: sessionId,\r\n project_token: projectToken,\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\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 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\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\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 switch (type) {\r\n case 'create_issue':\r\n templateName = 'create_issue';\r\n templateVariables = {\r\n selectedText: this.selectedText,\r\n currentDomain: document.location.hostname || '',\r\n buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'),\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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'all_issues':\r\n templateName = 'all_issues';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'concrete_issue':\r\n templateName = 'concrete_issue';\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\r\n switch (type) {\r\n case 'create_issue':\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 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 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\r\n case 'concrete_issue':\r\n\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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', () => {\r\n this.hide();\r\n }) || '';\r\n\r\n document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n const widget = document.querySelector('.doboard_task_widget-wrap');\r\n widget.classList.add('hidden');\r\n storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:360px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;justify-content:space-between;align-items:center;color:#FFF}.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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count:hover{background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHZpZXdCb3g9IjAgMCAyMiAyMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxmb3JlaWduT2JqZWN0IHg9Ii00IiB5PSItNCIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIj48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iYmFja2Ryb3AtZmlsdGVyOmJsdXIoMnB4KTtjbGlwLXBhdGg6dXJsKCNiZ2JsdXJfMF8xODk4OV8yODI2X2NsaXBfcGF0aCk7aGVpZ2h0OjEwMCU7d2lkdGg6MTAwJSI+PC9kaXY+PC9mb3JlaWduT2JqZWN0PjxwYXRoIGRhdGEtZmlnbWEtYmctYmx1ci1yYWRpdXM9IjQiIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjciLz4KICAgIDxwYXRoIGQ9Ik0xNiA2TDYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxwYXRoIGQ9Ik02IDZMMTYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxkZWZzPgogICAgICAgIDxjbGlwUGF0aCBpZD0iYmdibHVyXzBfMTg5ODlfMjgyNl9jbGlwX3BhdGgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgNCkiPjxwYXRoIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIi8+CiAgICAgICAgPC9jbGlwUGF0aD48L2RlZnM+Cjwvc3ZnPg==) center no-repeat;cursor:pointer;overflow:hidden;font-size:0}#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:40px}.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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`;\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\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 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
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 If you found issue with {{currentDomain}} page, you are in right place. Please use this form to tell us about the issue you’re experiencing.\r\n doboard.com\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 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 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 logoDoBoardWhite() {\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\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","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","confirmUserEmail","pendingTaskRaw","setItem","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","removeItem","getTasksFullDetails","currentActiveTaskId","length","find","item","sign","window","location","href","addTaskComment","err","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","addEventListener","taskTitleElement","value","taskDescriptionElement","loginSectionElement","contains","userEmailElement","userNameElement","userPasswordElement","style","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issueTitleElement","currentTaskData","String","issuesCommentsContainer","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","Number","commentUserId","commentAuthorAvatarSrc","commentAuthorName","commentData","commentTime","issueMessageClassOwner","daysWrapperHTML","day","messageId","currentDayMessages","dayMessagesWrapperHTML","localeCompare","currentMessageTemplateVariables","dayContentMonthDay","dayContentMessages","textarea","handleTextareaChange","setTimeout","contentContainer","scrollTo","top","scrollHeight","behavior","sendButton","widgetClass","preventDefault","input","closest","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","hide","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","toggle","handleScroll","bind","handleResize","messageText","titleSpan","messageDiv","messageWrap","color","widget","widgetCreateIssue","widgetConcreteIssue","scrollY","viewportHeight","innerHeight","selectionAbsoluteTop","getBoundingClientRect","widgetHeight","offsetHeight","bottom","clearTimeout","scrollTimeout","resizeTimeout","str","spotFixShowDelayTimeout","SPOTFIX_DEBUG","SPOTFIX_SHOW_DELAY","spotFixInit","SpotFixSourcesLoader","spotFixShowWidget","spotFixIsInsideWidget","node","el","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","display","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","s","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","position","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","container","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","wrap","wrap_review","fixedHtml","fixedTaskHtml","loadSVG","svgName","svgMethod","getAsRawSVG","svg","svgToDataURI","svgString","TextEncoder","encode","btoa","fromCharCode","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 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 localStorage.setItem('spotfix_app_version', 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\tconst users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId);\r\n\t\treturn users[0] || {};\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\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\tlocalStorage.setItem('spotfix_widget_is_closed', '1');\r\n\t\trootElement.hide();\r\n\t};\r\n\tconst toggle = document.getElementById('widget_visibility');\r\n\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: '',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 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;\r\n templateVariables.email = user.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\r\n break;\r\n case 'concrete_issue':\r\n\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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('#spotfix_back_button')?.addEventListener('click', () => {\r\n this.createWidgetElement(this.type_name)\r\n }) || '';\r\n\r\n // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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\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 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
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 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
\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.com\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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","hide","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","style","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","Number","commentUserId","commentAuthorAvatarSrc","commentAuthorName","commentData","commentTime","issueMessageClassOwner","daysWrapperHTML","day","messageId","currentDayMessages","dayMessagesWrapperHTML","localeCompare","currentMessageTemplateVariables","dayContentMonthDay","dayContentMessages","textarea","handleTextareaChange","setTimeout","contentContainer","scrollTo","top","scrollHeight","behavior","sendButton","widgetClass","preventDefault","input","closest","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","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","clearTimeout","scrollTimeout","resizeTimeout","str","spotFixShowDelayTimeout","SPOTFIX_DEBUG","SPOTFIX_SHOW_DELAY","spotFixInit","SpotFixSourcesLoader","spotFixShowWidget","spotFixIsInsideWidget","node","el","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","display","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","position","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","container","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/api.js b/js/src/api.js index 1d8de21..9381308 100644 --- a/js/src/api.js +++ b/js/src/api.js @@ -230,11 +230,13 @@ const getTasksCommentsDoboard = async (sessionId, accountId, projectToken, statu })); }; -const getUserDoboard = async (sessionId, projectToken, accountId) => { +const getUserDoboard = async (sessionId, projectToken, accountId, userId) => { const data = { session_id: sessionId, project_token: projectToken, } + if (userId) data.user_id = userId; + const result = await spotfixApiCall(data, 'user_get', accountId); return result.users; @@ -277,3 +279,20 @@ const userUpdateDoboard = async (projectToken, accountId, sessionId, userId, tim success: true }; } + +const getReleaseVersion = async () => { + try { + const res = await fetch('https://api.github.com/repos/CleanTalk/SpotFix/releases'); + const data = await res.json(); + + if (data.length > 0 && data[0].tag_name) { + localStorage.setItem('spotfix_app_version', data[0].tag_name); + return data[0].tag_name; + } + + return null; + } catch (err) { + return null; + } +}; + diff --git a/js/src/handlers.js b/js/src/handlers.js index 8c9b2e9..aeccec9 100644 --- a/js/src/handlers.js +++ b/js/src/handlers.js @@ -51,6 +51,13 @@ async function getTasksFullDetails(params, tasks, currentActiveTaskId) { } } +async function getUserDetails(params) { + const sessionId = localStorage.getItem('spotfix_session_id'); + const currentUserId = localStorage.getItem('spotfix_user_id'); + const users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); + return users[0] || {}; +} + async function handleCreateTask(sessionId, taskDetails) { try { const result = await createTaskDoboard(sessionId, taskDetails); @@ -267,3 +274,12 @@ function spotFixSplitUrl(url) { } +function setToggleStatus(rootElement){ + const clickHandler = () => { + localStorage.setItem('spotfix_widget_is_closed', '1'); + rootElement.hide(); + }; + const toggle = document.getElementById('widget_visibility'); + toggle.checked = true; + toggle.addEventListener('click', clickHandler); +} diff --git a/js/src/loaders/SpotFixSVGLoader.js b/js/src/loaders/SpotFixSVGLoader.js index 6ad29c4..f9b750b 100644 --- a/js/src/loaders/SpotFixSVGLoader.js +++ b/js/src/loaders/SpotFixSVGLoader.js @@ -31,6 +31,13 @@ class SpotFixSVGLoader { `; } + static chevronBackDark() { + return ` + + +`; + } + static buttonCloseScreen() { return ` @@ -39,6 +46,14 @@ class SpotFixSVGLoader { `; } + static buttonCloseScreenDark() { + return ` + + + +`; + } + static buttonSendMessage() { return ` @@ -106,4 +121,43 @@ class SpotFixSVGLoader { `; } + + static iconEllipsesMore() { + return ` + + + +`; + } + + static iconAvatar() { + return ` + + + + + + + + +`; + } + + static iconEye() { + return ` + + + +`; + } + + static iconDoor() { + return ` + + + +`; + } } diff --git a/js/src/loaders/SpotFixTemplatesLoader.js b/js/src/loaders/SpotFixTemplatesLoader.js index 7ea57bc..6f852b0 100644 --- a/js/src/loaders/SpotFixTemplatesLoader.js +++ b/js/src/loaders/SpotFixTemplatesLoader.js @@ -19,7 +19,12 @@ class SpotFixTemplatesLoader { All spots - +
+ + + + +
@@ -45,7 +50,12 @@ class SpotFixTemplatesLoader { All {{issuesCounter}}
{{issueTitle}}
- +
+ + + + +
@@ -114,14 +124,19 @@ class SpotFixTemplatesLoader { Report an issue
- +
+ + + + +
- If you found issue with {{currentDomain}} page, you are in right place. Please use this form to tell us about the issue you’re experiencing. - doboard.com + Tell us about any issue you’re experiencing on {{currentDomain}}. + You’re also welcome to review spelling, grammar, or ask a question related to this page.
@@ -204,6 +219,63 @@ class SpotFixTemplatesLoader { `; } + static user_menu() { + return ` +
+
+
+
+ + Back +
+
+ +
+
+
+ + {{userName}} + {{email}} +
+
+
+
+
+
+ +
+ + + Show widget on my screen + + The widget will be visible again if you select any text on the site + + +
+
+
+ +
+ Log out +
+
+
+
+
+ {{spotfixVersion}} + Powered by + + doboard.com + +
+
+
`; + } + static wrap() { return `
diff --git a/js/src/widget.js b/js/src/widget.js index 5929225..71db9bb 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -21,6 +21,7 @@ class CleanTalkWidgetDoboard { this.init(type); this.srcVariables = { buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), + iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'), buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'), buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'), @@ -278,10 +279,12 @@ class CleanTalkWidgetDoboard { switch (type) { case 'create_issue': templateName = 'create_issue'; + this.type_name = templateName; templateVariables = { selectedText: this.selectedText, currentDomain: document.location.hostname || '', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), + iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), ...this.srcVariables }; storageGetUserIsDefined() && storageSetWidgetIsClosed(false); @@ -299,10 +302,26 @@ class CleanTalkWidgetDoboard { break; case 'all_issues': templateName = 'all_issues'; + this.type_name = templateName; templateVariables = {...this.srcVariables}; break; + case 'user_menu': + templateName = 'user_menu'; + const versionFromLS = localStorage.getItem('spotfix_app_version'); + templateVariables = { + spotfixVersion: versionFromLS ? 'Spotfix version ' + versionFromLS + '.' : '', + avatar: SpotFixSVGLoader.getAsDataURI('iconAvatar'), + iconEye: SpotFixSVGLoader.getAsDataURI('iconEye'), + iconDoor: SpotFixSVGLoader.getAsDataURI('iconDoor'), + chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'), + buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'), + userName: '', + email: '', + ...this.srcVariables}; + break; case 'concrete_issue': templateName = 'concrete_issue'; + this.type_name = templateName; // Update the number of tasks this.savedIssuesQuantityAll = Array.isArray(this.allTasksData) ? this.allTasksData.length : 0; // Calculate the number of issues on the current page @@ -473,7 +492,28 @@ class CleanTalkWidgetDoboard { this.bindIssuesClick(); hideContainersSpinner(false); break; + case 'user_menu': + + setToggleStatus(this); + const user = await getUserDetails(this.params); + const gitHubAppVersion = await getReleaseVersion(); + let spotfixVersion = ''; + const version = localStorage.getItem('spotfix_app_version') || gitHubAppVersion; + spotfixVersion = version ? `Spotfix version ${version}.` : ''; + + templateVariables.spotfixVersion = spotfixVersion || ''; + if(user){ + templateVariables.userName = user.name; + templateVariables.email = user.email; + if(user?.avatar?.s) templateVariables.avatar = user?.avatar?.s; + } + + widgetContainer.innerHTML = this.loadTemplate('user_menu', templateVariables); + document.body.appendChild(widgetContainer); + setToggleStatus(this); + + break; case 'concrete_issue': tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId); @@ -656,16 +696,24 @@ class CleanTalkWidgetDoboard { this.fileUploader.bindPaperClipAction(paperclipController); } - document.querySelector('.doboard_task_widget-close_btn')?.addEventListener('click', () => { + document.querySelector('.doboard_task_widget-close_btn')?.addEventListener('click', (e) => { this.hide(); }) || ''; - document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => { - const widget = document.querySelector('.doboard_task_widget-wrap'); - widget.classList.add('hidden'); - storageSetWidgetIsClosed(true); + document.querySelector('#openUserMenuButton')?.addEventListener('click', () => { + this.createWidgetElement('user_menu') }) || ''; + document.querySelector('#spotfix_back_button')?.addEventListener('click', () => { + this.createWidgetElement(this.type_name) + }) || ''; + + // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => { + // const widget = document.querySelector('.doboard_task_widget-wrap'); + // widget.classList.add('hidden'); + // storageSetWidgetIsClosed(true); + // }) || ''; + return widgetContainer; } diff --git a/styles/doboard-widget.css b/styles/doboard-widget.css index d574d7b..197d6fa 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -81,7 +81,7 @@ } .doboard_task_widget-container { - width: 360px; + width: 400px; max-height: calc(100vh - 40px); display: flex; flex-direction: column; @@ -106,6 +106,34 @@ color: #FFFFFF; } +.doboard_task_widget-user_menu-header { + display: flex; + padding: 16px 16px; + border: 1px #BBC7D1 solid; + 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-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; @@ -200,12 +228,12 @@ } /*** We still find no way to keep inlined SVG. ***/ -#doboard_task_widget-task_count:hover { - background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHZpZXdCb3g9IjAgMCAyMiAyMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxmb3JlaWduT2JqZWN0IHg9Ii00IiB5PSItNCIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIj48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iYmFja2Ryb3AtZmlsdGVyOmJsdXIoMnB4KTtjbGlwLXBhdGg6dXJsKCNiZ2JsdXJfMF8xODk4OV8yODI2X2NsaXBfcGF0aCk7aGVpZ2h0OjEwMCU7d2lkdGg6MTAwJSI+PC9kaXY+PC9mb3JlaWduT2JqZWN0PjxwYXRoIGRhdGEtZmlnbWEtYmctYmx1ci1yYWRpdXM9IjQiIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjciLz4KICAgIDxwYXRoIGQ9Ik0xNiA2TDYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxwYXRoIGQ9Ik02IDZMMTYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxkZWZzPgogICAgICAgIDxjbGlwUGF0aCBpZD0iYmdibHVyXzBfMTg5ODlfMjgyNl9jbGlwX3BhdGgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgNCkiPjxwYXRoIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIi8+CiAgICAgICAgPC9jbGlwUGF0aD48L2RlZnM+Cjwvc3ZnPg==) no-repeat center; - cursor: pointer; - overflow: hidden; - font-size: 0; -} +/*#doboard_task_widget-task_count:hover {*/ +/* background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHZpZXdCb3g9IjAgMCAyMiAyMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxmb3JlaWduT2JqZWN0IHg9Ii00IiB5PSItNCIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIj48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iYmFja2Ryb3AtZmlsdGVyOmJsdXIoMnB4KTtjbGlwLXBhdGg6dXJsKCNiZ2JsdXJfMF8xODk4OV8yODI2X2NsaXBfcGF0aCk7aGVpZ2h0OjEwMCU7d2lkdGg6MTAwJSI+PC9kaXY+PC9mb3JlaWduT2JqZWN0PjxwYXRoIGRhdGEtZmlnbWEtYmctYmx1ci1yYWRpdXM9IjQiIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjciLz4KICAgIDxwYXRoIGQ9Ik0xNiA2TDYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxwYXRoIGQ9Ik02IDZMMTYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxkZWZzPgogICAgICAgIDxjbGlwUGF0aCBpZD0iYmdibHVyXzBfMTg5ODlfMjgyNl9jbGlwX3BhdGgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgNCkiPjxwYXRoIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIi8+CiAgICAgICAgPC9jbGlwUGF0aD48L2RlZnM+Cjwvc3ZnPg==) no-repeat center;*/ +/* cursor: pointer;*/ +/* overflow: hidden;*/ +/* font-size: 0;*/ +/*}*/ #doboard_task_widget-task_count.hidden { width: 0; @@ -275,7 +303,7 @@ border: 1px solid #BBC7D1; border-radius: 4px; padding: 11px 8px 8px 8px; - margin-bottom: 40px; + margin-bottom: 24px; } .doboard_task_widget-login.hidden { @@ -1158,4 +1186,54 @@ .doboard_task_widget-text_selection_tooltip_element { display: flex; justify-content: space-between; -} \ No newline at end of file +} + +.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: 0.3s; +} + +.slider:before { + content: ""; + position: absolute; + height: 24px; + width: 24px; + left: 2px; + top: 2px; + background-color: white; + border-radius: 50%; + transition: 0.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; +} From 379d1e67927a6023a296a5afcb5e939c871540f7 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Thu, 18 Dec 2025 01:06:36 +0400 Subject: [PATCH 02/20] Fix. Increased padding. --- dist/doboard-widget-bundle.js | 2 +- dist/doboard-widget-bundle.min.js | 2 +- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/loaders/SpotFixTemplatesLoader.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index f013fd3..c7b6961 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -3413,7 +3413,7 @@ class SpotFixTemplatesLoader {
- -
+
{{spotfixVersion}} Powered by diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 0841bf3..a9b1a0c 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 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 localStorage.setItem('spotfix_app_version', 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\tconst users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId);\r\n\t\treturn users[0] || {};\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\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\tlocalStorage.setItem('spotfix_widget_is_closed', '1');\r\n\t\trootElement.hide();\r\n\t};\r\n\tconst toggle = document.getElementById('widget_visibility');\r\n\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: '',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 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;\r\n templateVariables.email = user.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\r\n break;\r\n case 'concrete_issue':\r\n\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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('#spotfix_back_button')?.addEventListener('click', () => {\r\n this.createWidgetElement(this.type_name)\r\n }) || '';\r\n\r\n // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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\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 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
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 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
\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.com\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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","hide","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","style","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","Number","commentUserId","commentAuthorAvatarSrc","commentAuthorName","commentData","commentTime","issueMessageClassOwner","daysWrapperHTML","day","messageId","currentDayMessages","dayMessagesWrapperHTML","localeCompare","currentMessageTemplateVariables","dayContentMonthDay","dayContentMessages","textarea","handleTextareaChange","setTimeout","contentContainer","scrollTo","top","scrollHeight","behavior","sendButton","widgetClass","preventDefault","input","closest","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","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","clearTimeout","scrollTimeout","resizeTimeout","str","spotFixShowDelayTimeout","SPOTFIX_DEBUG","SPOTFIX_SHOW_DELAY","spotFixInit","SpotFixSourcesLoader","spotFixShowWidget","spotFixIsInsideWidget","node","el","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","display","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","position","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","container","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 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 localStorage.setItem('spotfix_app_version', 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\tconst users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId);\r\n\t\treturn users[0] || {};\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\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\tlocalStorage.setItem('spotfix_widget_is_closed', '1');\r\n\t\trootElement.hide();\r\n\t};\r\n\tconst toggle = document.getElementById('widget_visibility');\r\n\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: '',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 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;\r\n templateVariables.email = user.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\r\n break;\r\n case 'concrete_issue':\r\n\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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('#spotfix_back_button')?.addEventListener('click', () => {\r\n this.createWidgetElement(this.type_name)\r\n }) || '';\r\n\r\n // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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\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 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
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 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
\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.com\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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","hide","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","style","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","Number","commentUserId","commentAuthorAvatarSrc","commentAuthorName","commentData","commentTime","issueMessageClassOwner","daysWrapperHTML","day","messageId","currentDayMessages","dayMessagesWrapperHTML","localeCompare","currentMessageTemplateVariables","dayContentMonthDay","dayContentMessages","textarea","handleTextareaChange","setTimeout","contentContainer","scrollTo","top","scrollHeight","behavior","sendButton","widgetClass","preventDefault","input","closest","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","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","clearTimeout","scrollTimeout","resizeTimeout","str","spotFixShowDelayTimeout","SPOTFIX_DEBUG","SPOTFIX_SHOW_DELAY","spotFixInit","SpotFixSourcesLoader","spotFixShowWidget","spotFixIsInsideWidget","node","el","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","display","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","position","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","container","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 6f852b0..c52b8c5 100644 --- a/js/src/loaders/SpotFixTemplatesLoader.js +++ b/js/src/loaders/SpotFixTemplatesLoader.js @@ -265,7 +265,7 @@ class SpotFixTemplatesLoader { -
+
{{spotfixVersion}} Powered by From 4b92c727317b533b0e649f9d86591e0f2958ccde Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Thu, 18 Dec 2025 01:19:11 +0400 Subject: [PATCH 03/20] Fix. Increased closing time. --- dist/doboard-widget-bundle.js | 9 ++++++--- dist/doboard-widget-bundle.min.js | 4 ++-- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/handlers.js | 7 +++++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index c7b6961..e83a305 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -575,8 +575,11 @@ function spotFixSplitUrl(url) { function setToggleStatus(rootElement){ const clickHandler = () => { - localStorage.setItem('spotfix_widget_is_closed', '1'); - rootElement.hide(); + const timer = setTimeout(() => { + localStorage.setItem('spotfix_widget_is_closed', '1'); + rootElement.hide(); + clearTimeout(timer); + }, 300); }; const toggle = document.getElementById('widget_visibility'); toggle.checked = true; @@ -2016,6 +2019,7 @@ function ksesFilter(html, options = false) { return doc.body.innerHTML; } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`; /** * SELECTION will be grouped into three types: * 1 - Simple text within a single tag @@ -2575,7 +2579,6 @@ function spotFixRetrieveNodeFromPath(path) { return node; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index f48b441..258ebd2 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL
${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(e){var t=document.getElementById("widget_visibility");t.checked=!0,t.addEventListener("click",()=>{localStorage.setItem("spotfix_widget_is_closed","1"),e.hide()})}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,_=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this);p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name,l.email=p.email,p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this);break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:T,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId.toString()===t.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,_=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this);p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name,l.email=p.email,p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this);break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId.toString()===t.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let spotFixCSS=`.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`,SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index a9b1a0c..7a4f5ef 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 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 localStorage.setItem('spotfix_app_version', 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\tconst users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId);\r\n\t\treturn users[0] || {};\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\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\tlocalStorage.setItem('spotfix_widget_is_closed', '1');\r\n\t\trootElement.hide();\r\n\t};\r\n\tconst toggle = document.getElementById('widget_visibility');\r\n\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: '',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 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;\r\n templateVariables.email = user.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\r\n break;\r\n case 'concrete_issue':\r\n\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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('#spotfix_back_button')?.addEventListener('click', () => {\r\n this.createWidgetElement(this.type_name)\r\n }) || '';\r\n\r\n // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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\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 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
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 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
\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.com\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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","hide","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","style","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","Number","commentUserId","commentAuthorAvatarSrc","commentAuthorName","commentData","commentTime","issueMessageClassOwner","daysWrapperHTML","day","messageId","currentDayMessages","dayMessagesWrapperHTML","localeCompare","currentMessageTemplateVariables","dayContentMonthDay","dayContentMessages","textarea","handleTextareaChange","setTimeout","contentContainer","scrollTo","top","scrollHeight","behavior","sendButton","widgetClass","preventDefault","input","closest","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","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","clearTimeout","scrollTimeout","resizeTimeout","str","spotFixShowDelayTimeout","SPOTFIX_DEBUG","SPOTFIX_SHOW_DELAY","spotFixInit","SpotFixSourcesLoader","spotFixShowWidget","spotFixIsInsideWidget","node","el","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","display","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","position","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","container","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 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 localStorage.setItem('spotfix_app_version', 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\tconst users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId);\r\n\t\treturn users[0] || {};\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\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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: '',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 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;\r\n templateVariables.email = user.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\r\n break;\r\n case 'concrete_issue':\r\n\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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('#spotfix_back_button')?.addEventListener('click', () => {\r\n this.createWidgetElement(this.type_name)\r\n }) || '';\r\n\r\n // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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\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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:\"\";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`;\n/**\r\n * SELECTION will be grouped into three types:\r\n * 1 - Simple text within a single tag\r\n * 2 - Image tags\r\n * 3 - Any tag containing nested content\r\n * Each type will be processed differently.\r\n */\r\nconst SPOTFIX_SELECTION_TYPE_TEXT = 'text';\r\nconst SPOTFIX_SELECTION_TYPE_IMG = 'image';\r\nconst SPOTFIX_SELECTION_TYPE_ELEMENT = 'element';\r\n\r\n/**\r\n * Determines the type of selection\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {string|null} Selection type\r\n */\r\nfunction spotFixGetSelectionType(selection) {\r\n const range = selection.getRangeAt(0);\r\n const commonAncestor = range.commonAncestorContainer;\r\n\r\n // Case 1: Image selection\r\n if (spotFixGetSelectedImage(selection)) {\r\n return SPOTFIX_SELECTION_TYPE_IMG;\r\n }\r\n\r\n // Case 2: Element with nested content\r\n if (commonAncestor.nodeType === Node.ELEMENT_NODE &&\r\n commonAncestor.childNodes.length > 1 &&\r\n range.toString().trim() === '' &&\r\n range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE) {\r\n return SPOTFIX_SELECTION_TYPE_ELEMENT;\r\n }\r\n\r\n // Case 3: Simple text\r\n const hasTextContent = range.toString().trim().length > 0;\r\n const isTextNode = commonAncestor.nodeType === Node.TEXT_NODE;\r\n const isCollapsed = range.collapsed;\r\n\r\n if (hasTextContent && (isTextNode || !isCollapsed)) {\r\n return SPOTFIX_SELECTION_TYPE_TEXT;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extracts selection data from DOM Selection object\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {Object|null} Selection data with text, positions, URL and node path OR null (nothing)\r\n */\r\nfunction spotFixGetSelectedData(selection) {\r\n // Prechecks:\r\n // Selection not provided\r\n if (!selection) {spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection not provided`'); return null; }\r\n // Range not provided\r\n if (selection.rangeCount === 0) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Range not provided`'); return null; }\r\n // Several ranges provided\r\n if (selection.rangeCount > 1) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Several ranges provided`'); return null; }\r\n\r\n const range = selection.getRangeAt(0);\r\n // Selection must be within a single DOM element.\r\n if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }\r\n\r\n // FIRST - check selection type\r\n const selectionType = spotFixGetSelectionType(selection);\r\n\r\n // Selection type not determined\r\n if (!selectionType) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection type not determined`'); return null; }\r\n\r\n // SECOND - generate selectedData for each selectionType\r\n let selectedText = '';\r\n let startSelectPosition = 0;\r\n let endSelectPosition = 0;\r\n let nodePath = '';\r\n let imageUrl = '';\r\n\r\n const commonNode = range.commonAncestorContainer;\r\n\r\n switch (selectionType) {\r\n case SPOTFIX_SELECTION_TYPE_TEXT:\r\n if (range.toString().trim().length === 0) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection text is empty`');\r\n return null;\r\n }\r\n const commonNodeElement = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n selectedText = range.toString();\r\n startSelectPosition = range.startOffset;\r\n endSelectPosition = range.endOffset;\r\n if ( startSelectPosition === 0 && selectedText.length > endSelectPosition ) {\r\n endSelectPosition = selectedText.length;\r\n }\r\n nodePath = spotFixCalculateNodePath(commonNodeElement);\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_IMG:\r\n const imgElement = range.startContainer;\r\n const selectedImage = spotFixGetSelectedImage(selection);\r\n selectedText = `Image (${selectedImage.alt ? selectedImage.alt : 'no description'})`;\r\n nodePath = spotFixCalculateNodePath(selectedImage);\r\n // For images, positions represent the image element position in parent\r\n startSelectPosition = Array.from(imgElement.parentNode.children).indexOf(imgElement);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_ELEMENT:\r\n const element = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n if (element.childNodes.length <= 1) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection have not inner data`');\r\n return null;\r\n }\r\n selectedText = element.textContent || '';\r\n nodePath = spotFixCalculateNodePath(element);\r\n // For elements, positions represent the element's position in parent\r\n startSelectPosition = Array.from(element.parentNode.children).indexOf(element);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n }\r\n\r\n // Get page URL\r\n const pageURL = window.location.href;\r\n\r\n return {\r\n startSelectPosition,\r\n endSelectPosition,\r\n selectedText: selectedText.trim(),\r\n pageURL,\r\n nodePath,\r\n selectionType,\r\n imageUrl: selectionType === SPOTFIX_SELECTION_TYPE_IMG ? imageUrl : ''\r\n };\r\n}\r\n\r\n/**\r\n * Highlight elements.\r\n * @param {[object]} spotsToBeHighlighted\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightElements(spotsToBeHighlighted, widgetInstance) {\r\n\r\n if (spotsToBeHighlighted.length === 0) return;\r\n\r\n const elementsMap = new Map();\r\n\r\n // Grouping elements with validation\r\n spotsToBeHighlighted.forEach(spot => {\r\n // nodePath validating: is array\r\n if (!spot?.nodePath || !Array.isArray(spot?.nodePath)) {\r\n spotFixDebugLog('Invalid spot: missing or invalid nodePath: ' + spot);\r\n return;\r\n }\r\n\r\n // nodePath validating: is valid indexes list\r\n if (!this.spotFixIsValidNodePath(spot.nodePath)) {\r\n spotFixDebugLog('Invalid nodePath format: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n const element = spotFixRetrieveNodeFromPath(spot.nodePath);\r\n if (!element) {\r\n spotFixDebugLog('Element not found for path: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n if ( ! spot.selectionType ) {\r\n // @ToDo need to apply backward capability here\r\n // just `spot.selectionType = 'text';` is not able, this opens ability to unauthorized modify website content\r\n spotFixDebugLog('Selection type is not provided.');\r\n return;\r\n }\r\n\r\n // selectionType parameter validating\r\n if (\r\n spot.selectionType &&\r\n ![\r\n SPOTFIX_SELECTION_TYPE_TEXT,\r\n SPOTFIX_SELECTION_TYPE_IMG,\r\n SPOTFIX_SELECTION_TYPE_ELEMENT\r\n ].includes(spot.selectionType)\r\n ) {\r\n spotFixDebugLog('Invalid selection type: ' + spot.selectionType);\r\n return;\r\n }\r\n\r\n if (!elementsMap.has(element)) {\r\n elementsMap.set(element, []);\r\n }\r\n elementsMap.get(element).push(spot);\r\n });\r\n\r\n elementsMap.forEach((spots, element) => {\r\n const selectionType = spots[0].selectionType;\r\n\r\n // MAIN LOGIC: highlight for the different types\r\n switch (selectionType) {\r\n case 'image':\r\n this.spotFixHighlightImageElement(element);\r\n break;\r\n\r\n case 'element':\r\n this.spotFixHighlightNestedElement(element);\r\n break;\r\n\r\n case 'text':\r\n this.spotFixHighlightTextInElement(element, spots, widgetInstance);\r\n break;\r\n\r\n default:\r\n spotFixDebugLog('Unknown selection type: ' + selectionType);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Highlight image element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightImageElement(element) {\r\n if (element.tagName !== 'IMG') {\r\n spotFixDebugLog('Expected IMG element for image highlight, got: ' + element.tagName);\r\n return;\r\n }\r\n element.classList.add('doboard_task_widget-image_selection');\r\n}\r\n\r\n/**\r\n * Highlight nested element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightNestedElement(element) {\r\n element.classList.add('doboard_task_widget-element_selection');\r\n}\r\n\r\n/**\r\n * Highlight text in element with span wrapping\r\n * @param {Element} element\r\n * @param {Array} spots\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightTextInElement(element, spots,widgetInstance) {\r\n let tooltipTitleText = '';\r\n if (spots[0].isFixed) {\r\n tooltipTitleText = `This issue already fixed.`;\r\n } else {\r\n tooltipTitleText = `We are already working on this issue.`;\r\n }\r\n\r\n const tooltip = `
\r\n \r\n \r\n
${tooltipTitleText}
\r\n
You can see history Here
\r\n
\r\n
`;\r\n\r\n const spotfixHighlightOpen = `${tooltip}`;\r\n const spotfixHighlightClose = ``;\r\n\r\n let text = element.textContent;\r\n const spotSelectedText = spots[0].selectedText;\r\n\r\n // meta.selectedText can not be empty string\r\n if ( ! spotSelectedText ) {\r\n spotFixDebugLog('Provided metadata is invalid.');\r\n return;\r\n }\r\n\r\n const markers = [];\r\n\r\n // Mark positions for inserting\r\n spots.forEach(spot => {\r\n // Validating positions\r\n const startPos = parseInt(spot.startSelectPosition) || 0;\r\n const endPos = parseInt(spot.endSelectPosition) || 0;\r\n\r\n if (startPos < 0 || endPos > text.length || startPos > endPos) {\r\n spotFixDebugLog('Invalid text positions: ' + spot);\r\n return;\r\n }\r\n\r\n markers.push({ position: startPos, type: 'start' });\r\n markers.push({ position: endPos, type: 'end' });\r\n });\r\n\r\n if (markers.length === 0) return;\r\n\r\n // Sort markers backward\r\n markers.sort((a, b) => b.position - a.position);\r\n\r\n // Check here that element (from meta.nodePath) contains same inner text as in meta.selectedText\r\n // Is the `text` in the element equal to the selected text `spotSelectedText`\r\n if ( text.slice(markers[1].position, markers[0].position) !== spotSelectedText ) {\r\n spotFixDebugLog('It is not allow to highlight element by provided metadata.');\r\n return;\r\n }\r\n\r\n let result = text;\r\n markers.forEach(marker => {\r\n const insertText = marker.type === 'start'\r\n ? spotfixHighlightOpen\r\n : spotfixHighlightClose;\r\n\r\n result = result.slice(0, marker.position) + insertText + result.slice(marker.position);\r\n });\r\n\r\n // Safety HTML insert\r\n try {\r\n element.innerHTML = ksesFilter(result);\r\n document.querySelectorAll('.doboard_task_widget-see-task').forEach(link => {\r\n link.addEventListener('click', (e) => {\r\n\r\n e.preventDefault();\r\n const classList = link.className.split(' ');\r\n const idClass = classList.find(cls => cls.includes('__task-id-'));\r\n let taskId = null;\r\n if (idClass) {\r\n taskId = idClass.split('__task-id-')[1];\r\n }\r\n if (taskId) {\r\n widgetInstance.currentActiveTaskId = taskId;\r\n widgetInstance.showOneTask();\r\n }\r\n });\r\n });\r\n } catch (error) {\r\n spotFixDebugLog('Error updating element content: ' + error);\r\n }\r\n}\r\n\r\n/**\r\n * Scroll to an element by tag, class, and text content\r\n * @param {array} path - The path to the element\r\n * @return {boolean} - True if the element was found and scrolled to, false otherwise\r\n */\r\nfunction spotFixScrollToNodePath(path) {\r\n const node = spotFixRetrieveNodeFromPath(path);\r\n if (node && node.scrollIntoView) {\r\n node.scrollIntoView({ behavior: 'smooth', block: 'center' });\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction spotFixRemoveHighlights() {\r\n const textSelectionclassName = 'doboard_task_widget-text_selection';\r\n const spans = document.querySelectorAll('.' + textSelectionclassName);\r\n const affectedParents = new Set(); // Track unique parents\r\n\r\n spans.forEach(span => {\r\n const parent = span.parentNode;\r\n affectedParents.add(parent); // Mark parent as affected\r\n const tooltip = span.querySelector('.doboard_task_widget-text_selection_tooltip');\r\n if (tooltip) tooltip.remove();\r\n\r\n // Move all child nodes out of the span and into the parent\r\n while (span.firstChild) {\r\n parent.insertBefore(span.firstChild, span);\r\n }\r\n parent.removeChild(span);\r\n });\r\n\r\n // Normalize all affected parents to merge adjacent text nodes\r\n affectedParents.forEach(parent => parent.normalize());\r\n\r\n const elementSelectionClassName = 'doboard_task_widget-element_selection';\r\n const elements = document.querySelectorAll(`.${elementSelectionClassName}`);\r\n elements.forEach(element => {\r\n element.classList.remove(elementSelectionClassName);\r\n });\r\n const imageSelectionClassName = 'doboard_task_widget-image_selection';\r\n const images = document.querySelectorAll(`.${imageSelectionClassName}`);\r\n images.forEach(element => {\r\n element.classList.remove(imageSelectionClassName);\r\n });\r\n}\r\n\r\n/**\r\n * Validate nodePath as array of indices\r\n * @param {Array} nodePath\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsValidNodePath(nodePath) {\r\n if (!Array.isArray(nodePath)) return false;\r\n if (nodePath.length === 0) return false;\r\n\r\n return nodePath.every(index => {\r\n return Number.isInteger(index) && index >= 0 && index < 1000;\r\n });\r\n}\r\n\r\n/**\r\n * Try to find selected image in selection.\r\n * @param selection\r\n * @returns {Node|*|null}\r\n */\r\nfunction spotFixGetSelectedImage(selection) {\r\n\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\r\n return null;\r\n }\r\n\r\n const range = selection.getRangeAt(0);\r\n\r\n // Is current end container IMG\r\n if (range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE &&\r\n range.startContainer.tagName === 'IMG') {\r\n return range.startContainer;\r\n }\r\n\r\n // Get img in the range\r\n const walker = document.createTreeWalker(\r\n range.commonAncestorContainer,\r\n NodeFilter.SHOW_ELEMENT,\r\n {\r\n acceptNode: function(node) {\r\n return node.tagName === 'IMG' &&\r\n spotFixIsElementInRange(node, range) ?\r\n NodeFilter.FILTER_ACCEPT :\r\n NodeFilter.FILTER_REJECT;\r\n }\r\n }\r\n );\r\n\r\n let imgNode = walker.nextNode();\r\n if (imgNode) {\r\n return imgNode;\r\n }\r\n\r\n // start/end containers\r\n const startElement = spotFixGetElementFromNode(range.startContainer);\r\n const endElement = spotFixGetElementFromNode(range.endContainer);\r\n\r\n // If selection starts on image\r\n if (startElement && startElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(startElement, range)) {\r\n return startElement;\r\n }\r\n\r\n if (endElement && endElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(endElement, range)) {\r\n return endElement;\r\n }\r\n\r\n // 4. Get closest IMG\r\n const nearbyElements = spotFixFindNearbyElements(range);\r\n for (const element of nearbyElements) {\r\n if (element.tagName === 'IMG') {\r\n return element;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction spotFixIsElementInRange(element, range) {\r\n const elementRange = document.createRange();\r\n elementRange.selectNode(element);\r\n return range.compareBoundaryPoints(Range.START_TO_START, elementRange) <= 0 &&\r\n range.compareBoundaryPoints(Range.END_TO_END, elementRange) >= 0;\r\n}\r\n\r\nfunction spotFixIsElementPartiallySelected(element, range) {\r\n const elementRect = element.getBoundingClientRect();\r\n const rangeRect = range.getBoundingClientRect();\r\n\r\n // bounding rectangles is crossed\r\n return !(elementRect.right < rangeRect.left ||\r\n elementRect.left > rangeRect.right ||\r\n elementRect.bottom < rangeRect.top ||\r\n elementRect.top > rangeRect.bottom);\r\n}\r\n\r\nfunction spotFixGetElementFromNode(node) {\r\n return node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n}\r\n\r\n/**\r\n * Find nearby elements in the range.\r\n * @param range\r\n * @returns {*[]}\r\n */\r\nfunction spotFixFindNearbyElements(range) {\r\n const elements = [];\r\n const container = range.commonAncestorContainer;\r\n\r\n // search elements\r\n const previousElement = container.previousElementSibling;\r\n const nextElement = container.nextElementSibling;\r\n\r\n if (previousElement) {\r\n elements.push(previousElement);\r\n }\r\n if (nextElement) {\r\n elements.push(nextElement);\r\n }\r\n\r\n // Also check child container\r\n if (container.nodeType === Node.ELEMENT_NODE) {\r\n const children = container.children;\r\n for (let i = 0; i < children.length; i++) {\r\n if (spotFixIsElementPartiallySelected(children[i], range)) {\r\n elements.push(children[i]);\r\n }\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Calculate the path of a DOM node\r\n *\r\n * @param {Node} node\r\n * @return {int[]}\r\n */\r\nfunction spotFixCalculateNodePath(node) {\r\n let path = [];\r\n while (node) {\r\n let index = 0;\r\n let sibling = node.previousSibling;\r\n while (sibling) {\r\n if (sibling.nodeType === 1) {\r\n index++;\r\n }\r\n sibling = sibling.previousSibling;\r\n }\r\n path.unshift(index);\r\n node = node.parentNode;\r\n }\r\n\r\n // Hard fix - need to remove first element to work correctly\r\n path.shift();\r\n\r\n return path;\r\n}\r\n\r\n/**\r\n * Retrieve a DOM node from a path\r\n *\r\n * @param {int[]} path\r\n * @return {*|null}\r\n */\r\nfunction spotFixRetrieveNodeFromPath(path) {\r\n // @ToDo check if the path is correct\r\n if ( ! path ) {\r\n return null;\r\n }\r\n\r\n let node = document;\r\n for (let i = 0; i < path.length; i++) {\r\n node = node.children[path[i]];\r\n if ( ! node ) {\r\n return null;\r\n }\r\n }\r\n return node;\r\n}\r\n\n/**\r\n * Return bool if widget is closed in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetWidgetIsClosed() {\r\n return localStorage.getItem('spotfix_widget_is_closed') === '1';\r\n}\r\n\r\n/**\r\n * Return bool if widget closed state is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageWidgetCloseIsSet() {\r\n return localStorage.getItem('spotfix_widget_is_closed') !== null;\r\n}\r\n\r\n/**\r\n * Save widget closed state\r\n * @param visible\r\n */\r\nfunction storageSetWidgetIsClosed(visible) {\r\n localStorage.setItem('spotfix_widget_is_closed', visible ? '1' : '0');\r\n}\r\n\r\n/**\r\n * Return bool if user is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetUserIsDefined() {\r\n return localStorage.getItem('spotfix_user_id') !== null;\r\n}\r\n\r\n/**\r\n * Save data for updates check\r\n * @param tasks\r\n */\r\nfunction storageSaveTasksUpdateData(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n\r\n tasks.forEach(task => {\r\n if (task.taskId && task.taskLastUpdate) {\r\n storedTasks[task.taskId] = {\r\n taskId: task.taskId,\r\n taskLastUpdate: task.taskLastUpdate\r\n };\r\n }\r\n });\r\n\r\n localStorage.setItem('spotfix_task_updates', JSON.stringify(storedTasks));\r\n}\r\n\r\nfunction storageSaveTasksCount(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n const count = tasks.filter(task => {\r\n return task.taskMeta;\r\n })?.length;\r\n\r\n localStorage.setItem('spotfix_tasks_count', `${count}`);\r\n}\r\n\r\n/**\r\n * Check if a specific task has been updated since last check\r\n * @param taskId\r\n * @param currentLastUpdate\r\n * @returns {boolean|null}\r\n */\r\nfunction storageCheckTaskUpdate(taskId, currentLastUpdate) {\r\n if (!taskId || !currentLastUpdate) {\r\n return null;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n const storedTask = storedTasks[taskId];\r\n\r\n if (!storedTask) {\r\n return false;\r\n }\r\n\r\n const storedUpdate = new Date(storedTask.taskLastUpdate);\r\n const currentUpdate = new Date(currentLastUpdate);\r\n return currentUpdate > storedUpdate;\r\n}\r\n\r\n/**\r\n * Add unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageAddUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n if (!storedUnread.includes(taskId)) {\r\n storedUnread.push(taskId);\r\n }\r\n\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Remove unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageRemoveUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n storedUnread = storedUnread.filter(id => id !== taskId);\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Check if there are any unread updates\r\n * @returns {boolean}\r\n */\r\nfunction storageTasksHasUnreadUpdates() {\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.length > 0;\r\n}\r\n\r\n/**\r\n * Check if a specific task has unread updates\r\n * @param taskId\r\n * @returns {boolean}\r\n */\r\nfunction storageProvidedTaskHasUnreadUpdates(taskId) {\r\n if (!taskId) {\r\n return false;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.includes(taskId.toString());\r\n}\r\n\r\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 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
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 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
\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.com\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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","style","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","closest","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","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","spotFixShowWidget","spotFixIsInsideWidget","node","el","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","display","containerClassesToShow","containers","tasksDetails","lastComment","dt","avatarSrc","authorName","authorDetails","charAt","toUpperCase","isAnyTaskUpdated","updatedtasksIDS","currentStateOfTask","issuerId","storageCheckTaskUpdate","updatedTaskIDs","lastMessage","updatedTaskId","updatedTaskData","storageAddUnreadUpdateForTaskID","isSelectionCorrect","html","options","allowedTags","strong","em","ul","ol","li","p","br","span","blockquote","pre","div","img","label","button","details","summary","allowedAttrs","doc","DOMParser","parseFromString","childNodes","clean","tag","tagName","toLowerCase","link","alt","target","parentNode","insertBefore","textContent","attributes","attr","attrName","startsWith","readyState","sel","isWrapReviewWidgetExists","focusNode","anchorNode","spotFixCSS","SPOTFIX_SELECTION_TYPE_TEXT","SPOTFIX_SELECTION_TYPE_IMG","SPOTFIX_SELECTION_TYPE_ELEMENT","spotFixGetSelectionType","range","getRangeAt","commonAncestor","commonAncestorContainer","spotFixGetSelectedImage","startContainer","endContainer","hasTextContent","isTextNode","TEXT_NODE","isCollapsed","collapsed","rangeCount","selectionType","startSelectPosition","endSelectPosition","commonNode","commonNodeElement","startOffset","endOffset","spotFixCalculateNodePath","imgElement","selectedImage","from","children","indexOf","imageUrl","widgetInstance","elementsMap","Map","spot","spotFixIsValidNodePath","spotFixRetrieveNodeFromPath","has","set","spots","spotFixHighlightImageElement","spotFixHighlightNestedElement","spotFixHighlightTextInElement","tooltipTitleText","spotfixHighlightOpen","text","spotSelectedText","markers","startPos","parseInt","endPos","position","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","container","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","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/handlers.js b/js/src/handlers.js index aeccec9..4f155e5 100644 --- a/js/src/handlers.js +++ b/js/src/handlers.js @@ -276,8 +276,11 @@ function spotFixSplitUrl(url) { function setToggleStatus(rootElement){ const clickHandler = () => { - localStorage.setItem('spotfix_widget_is_closed', '1'); - rootElement.hide(); + const timer = setTimeout(() => { + localStorage.setItem('spotfix_widget_is_closed', '1'); + rootElement.hide(); + clearTimeout(timer); + }, 300); }; const toggle = document.getElementById('widget_visibility'); toggle.checked = true; From cc8974797eb2983b998c83284f8f968cef18f354 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Thu, 18 Dec 2025 05:19:39 +0400 Subject: [PATCH 04/20] Upd. Added and renamed buttons --- dist/doboard-widget-bundle.js | 48 ++++++++++++++++++------ dist/doboard-widget-bundle.min.js | 19 ++++++---- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/handlers.js | 18 ++++++++- js/src/loaders/SpotFixTemplatesLoader.js | 15 +++++--- js/src/widget.js | 13 +++++-- styles/doboard-widget.css | 10 +++++ 7 files changed, 93 insertions(+), 32 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index e83a305..9a1975f 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -353,8 +353,10 @@ async function getTasksFullDetails(params, tasks, currentActiveTaskId) { async function getUserDetails(params) { const sessionId = localStorage.getItem('spotfix_session_id'); const currentUserId = localStorage.getItem('spotfix_user_id'); - const users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); - return users[0] || {}; + if(currentUserId) { + const users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); + return users[0] || {}; + } } async function handleCreateTask(sessionId, taskDetails) { @@ -586,6 +588,18 @@ function setToggleStatus(rootElement){ toggle.addEventListener('click', clickHandler); } +function checkLogInOutButtonsVisible (){ + if(!localStorage.getItem('spotfix_session_id')) { + const el = document + .getElementById('doboard_task_widget-user_menu-logout_button') + .closest('.doboard_task_widget-user_menu-item'); + if(el) el.style.display = 'none'; + } else { + const el = document.getElementById('doboard_task_widget-user_menu-signlog_button'); + if(el) el.style.display = 'none'; + } +} + /** * Widget class to create a task widget */ @@ -903,7 +917,7 @@ class CleanTalkWidgetDoboard { iconDoor: SpotFixSVGLoader.getAsDataURI('iconDoor'), chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'), buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'), - userName: '', + userName: 'Guest', email: '', ...this.srcVariables}; break; @@ -1083,6 +1097,8 @@ class CleanTalkWidgetDoboard { case 'user_menu': setToggleStatus(this); + checkLogInOutButtonsVisible(); + const user = await getUserDetails(this.params); const gitHubAppVersion = await getReleaseVersion(); let spotfixVersion = ''; @@ -1092,14 +1108,15 @@ class CleanTalkWidgetDoboard { templateVariables.spotfixVersion = spotfixVersion || ''; if(user){ - templateVariables.userName = user.name; - templateVariables.email = user.email; + templateVariables.userName = user.name || 'Guest'; + templateVariables.email = user.email || ''; if(user?.avatar?.s) templateVariables.avatar = user?.avatar?.s; } widgetContainer.innerHTML = this.loadTemplate('user_menu', templateVariables); document.body.appendChild(widgetContainer); setToggleStatus(this); + checkLogInOutButtonsVisible(); break; case 'concrete_issue': @@ -1292,6 +1309,10 @@ class CleanTalkWidgetDoboard { this.createWidgetElement('user_menu') }) || ''; + document.querySelector('#doboard_task_widget-user_menu-signlog_button')?.addEventListener('click', () => { + spotFixShowWidget(); + }) || ''; + document.querySelector('#spotfix_back_button')?.addEventListener('click', () => { this.createWidgetElement(this.type_name) }) || ''; @@ -2019,7 +2040,6 @@ function ksesFilter(html, options = false) { return doc.body.innerHTML; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`; /** * SELECTION will be grouped into three types: * 1 - Simple text within a single tag @@ -2579,6 +2599,7 @@ function spotFixRetrieveNodeFromPath(path) { return node; } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} @@ -3185,7 +3206,7 @@ class SpotFixTemplatesLoader { @@ -3385,9 +3406,12 @@ class SpotFixTemplatesLoader {
- + {{userName}} {{email}} + + Sign up or Log in +
@@ -3409,10 +3433,10 @@ class SpotFixTemplatesLoader {
- -
+ + Log out -
+
@@ -3420,7 +3444,7 @@ class SpotFixTemplatesLoader { {{spotfixVersion}} Powered by - doboard.com + doBoard diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 258ebd2..64ce380 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,_=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this);p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name,l.email=p.email,p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this);break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId.toString()===t.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let spotFixCSS=`.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`,SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,u=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;i<_.length;i++){var m=_[i],h=m.taskId,w=m.taskTitle,b=m.taskMeta;let t=null;if(b)try{(t=JSON.parse(b)).isFixed="DONE"===m.taskStatus,t.taskId=m.taskId}catch(e){t=null}var k,x,b=t?t.pageURL:"",f=t?t.nodePath:"";let e="",a="Task publicity is unknown";t&&void 0!==t.isPublic&&(a=t.isPublic?(e=this.srcVariables.iconSpotPublic,"The task is public"):(e=this.srcVariables.iconSpotPrivate,"The task is private and visible only for registered DoBoard users")),b===window.location.href&&o++,r&&b!==window.location.href||(x=getAvatarData(k=getTaskFullDetails(n,h)),w={taskTitle:w||"",taskAuthorAvatarImgSrc:k.taskAuthorAvatarImgSrc,taskAuthorName:k.taskAuthorName,taskPublicStatusImgSrc:e,taskPublicStatusHint:a,taskLastMessage:ksesFilter(k.lastMessageText),taskPageUrl:b,iconLinkChain:this.srcVariables.iconLinkChain,taskFormattedPageUrl:spotFixSplitUrl(b),taskLastUpdate:k.lastMessageTime,nodePath:this.sanitizeNodePath(f),taskId:h,avatarCSSClass:x.avatarCSSClass,avatarStyle:x.avatarStyle,taskAuthorInitials:x.taskAuthorInitials,initialsClass:x.initialsClass,classUnread:"",elementBgCSSClass:"DONE"!==m.taskStatus?"":"doboard_task_widget-task_row-green",statusFixedHtml:"DONE"!==m.taskStatus?"":this.loadTemplate("fixedHtml")},storageProvidedTaskHasUnreadUpdates(k.taskId)&&(w.classUnread="unread"),document.querySelector(".doboard_task_widget-all_issues-container").innerHTML+=this.loadTemplate("list_issues",w),this.isSpotHaveToBeHighlighted(t)&&u.push(t))}this.savedIssuesQuantityOnPage=o,this.savedIssuesQuantityAll=g.length,spotFixHighlightElements(u,this),document.querySelector(".doboard_task_widget-header span").innerHTML+=ksesFilter(" "+getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll))}0===g.length&&(document.querySelector(".doboard_task_widget-all_issues-container").innerHTML=ksesFilter('
The issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name||"Guest",l.email=p.email||"",p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId.toString()===t.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
@@ -34,7 +34,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
@@ -210,9 +210,12 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
- + {{userName}} {{email}} + + Sign up or Log in +
@@ -234,10 +237,10 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
- -
+ + Log out -
+
@@ -245,7 +248,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) {{spotfixVersion}} Powered by - doboard.com + doBoard diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 7a4f5ef..d6cf966 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 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 localStorage.setItem('spotfix_app_version', 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\tconst users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId);\r\n\t\treturn users[0] || {};\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\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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: '',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 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;\r\n templateVariables.email = user.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\r\n break;\r\n case 'concrete_issue':\r\n\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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('#spotfix_back_button')?.addEventListener('click', () => {\r\n this.createWidgetElement(this.type_name)\r\n }) || '';\r\n\r\n // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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\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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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-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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:\"\";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`;\n/**\r\n * SELECTION will be grouped into three types:\r\n * 1 - Simple text within a single tag\r\n * 2 - Image tags\r\n * 3 - Any tag containing nested content\r\n * Each type will be processed differently.\r\n */\r\nconst SPOTFIX_SELECTION_TYPE_TEXT = 'text';\r\nconst SPOTFIX_SELECTION_TYPE_IMG = 'image';\r\nconst SPOTFIX_SELECTION_TYPE_ELEMENT = 'element';\r\n\r\n/**\r\n * Determines the type of selection\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {string|null} Selection type\r\n */\r\nfunction spotFixGetSelectionType(selection) {\r\n const range = selection.getRangeAt(0);\r\n const commonAncestor = range.commonAncestorContainer;\r\n\r\n // Case 1: Image selection\r\n if (spotFixGetSelectedImage(selection)) {\r\n return SPOTFIX_SELECTION_TYPE_IMG;\r\n }\r\n\r\n // Case 2: Element with nested content\r\n if (commonAncestor.nodeType === Node.ELEMENT_NODE &&\r\n commonAncestor.childNodes.length > 1 &&\r\n range.toString().trim() === '' &&\r\n range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE) {\r\n return SPOTFIX_SELECTION_TYPE_ELEMENT;\r\n }\r\n\r\n // Case 3: Simple text\r\n const hasTextContent = range.toString().trim().length > 0;\r\n const isTextNode = commonAncestor.nodeType === Node.TEXT_NODE;\r\n const isCollapsed = range.collapsed;\r\n\r\n if (hasTextContent && (isTextNode || !isCollapsed)) {\r\n return SPOTFIX_SELECTION_TYPE_TEXT;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extracts selection data from DOM Selection object\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {Object|null} Selection data with text, positions, URL and node path OR null (nothing)\r\n */\r\nfunction spotFixGetSelectedData(selection) {\r\n // Prechecks:\r\n // Selection not provided\r\n if (!selection) {spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection not provided`'); return null; }\r\n // Range not provided\r\n if (selection.rangeCount === 0) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Range not provided`'); return null; }\r\n // Several ranges provided\r\n if (selection.rangeCount > 1) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Several ranges provided`'); return null; }\r\n\r\n const range = selection.getRangeAt(0);\r\n // Selection must be within a single DOM element.\r\n if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }\r\n\r\n // FIRST - check selection type\r\n const selectionType = spotFixGetSelectionType(selection);\r\n\r\n // Selection type not determined\r\n if (!selectionType) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection type not determined`'); return null; }\r\n\r\n // SECOND - generate selectedData for each selectionType\r\n let selectedText = '';\r\n let startSelectPosition = 0;\r\n let endSelectPosition = 0;\r\n let nodePath = '';\r\n let imageUrl = '';\r\n\r\n const commonNode = range.commonAncestorContainer;\r\n\r\n switch (selectionType) {\r\n case SPOTFIX_SELECTION_TYPE_TEXT:\r\n if (range.toString().trim().length === 0) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection text is empty`');\r\n return null;\r\n }\r\n const commonNodeElement = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n selectedText = range.toString();\r\n startSelectPosition = range.startOffset;\r\n endSelectPosition = range.endOffset;\r\n if ( startSelectPosition === 0 && selectedText.length > endSelectPosition ) {\r\n endSelectPosition = selectedText.length;\r\n }\r\n nodePath = spotFixCalculateNodePath(commonNodeElement);\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_IMG:\r\n const imgElement = range.startContainer;\r\n const selectedImage = spotFixGetSelectedImage(selection);\r\n selectedText = `Image (${selectedImage.alt ? selectedImage.alt : 'no description'})`;\r\n nodePath = spotFixCalculateNodePath(selectedImage);\r\n // For images, positions represent the image element position in parent\r\n startSelectPosition = Array.from(imgElement.parentNode.children).indexOf(imgElement);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_ELEMENT:\r\n const element = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n if (element.childNodes.length <= 1) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection have not inner data`');\r\n return null;\r\n }\r\n selectedText = element.textContent || '';\r\n nodePath = spotFixCalculateNodePath(element);\r\n // For elements, positions represent the element's position in parent\r\n startSelectPosition = Array.from(element.parentNode.children).indexOf(element);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n }\r\n\r\n // Get page URL\r\n const pageURL = window.location.href;\r\n\r\n return {\r\n startSelectPosition,\r\n endSelectPosition,\r\n selectedText: selectedText.trim(),\r\n pageURL,\r\n nodePath,\r\n selectionType,\r\n imageUrl: selectionType === SPOTFIX_SELECTION_TYPE_IMG ? imageUrl : ''\r\n };\r\n}\r\n\r\n/**\r\n * Highlight elements.\r\n * @param {[object]} spotsToBeHighlighted\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightElements(spotsToBeHighlighted, widgetInstance) {\r\n\r\n if (spotsToBeHighlighted.length === 0) return;\r\n\r\n const elementsMap = new Map();\r\n\r\n // Grouping elements with validation\r\n spotsToBeHighlighted.forEach(spot => {\r\n // nodePath validating: is array\r\n if (!spot?.nodePath || !Array.isArray(spot?.nodePath)) {\r\n spotFixDebugLog('Invalid spot: missing or invalid nodePath: ' + spot);\r\n return;\r\n }\r\n\r\n // nodePath validating: is valid indexes list\r\n if (!this.spotFixIsValidNodePath(spot.nodePath)) {\r\n spotFixDebugLog('Invalid nodePath format: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n const element = spotFixRetrieveNodeFromPath(spot.nodePath);\r\n if (!element) {\r\n spotFixDebugLog('Element not found for path: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n if ( ! spot.selectionType ) {\r\n // @ToDo need to apply backward capability here\r\n // just `spot.selectionType = 'text';` is not able, this opens ability to unauthorized modify website content\r\n spotFixDebugLog('Selection type is not provided.');\r\n return;\r\n }\r\n\r\n // selectionType parameter validating\r\n if (\r\n spot.selectionType &&\r\n ![\r\n SPOTFIX_SELECTION_TYPE_TEXT,\r\n SPOTFIX_SELECTION_TYPE_IMG,\r\n SPOTFIX_SELECTION_TYPE_ELEMENT\r\n ].includes(spot.selectionType)\r\n ) {\r\n spotFixDebugLog('Invalid selection type: ' + spot.selectionType);\r\n return;\r\n }\r\n\r\n if (!elementsMap.has(element)) {\r\n elementsMap.set(element, []);\r\n }\r\n elementsMap.get(element).push(spot);\r\n });\r\n\r\n elementsMap.forEach((spots, element) => {\r\n const selectionType = spots[0].selectionType;\r\n\r\n // MAIN LOGIC: highlight for the different types\r\n switch (selectionType) {\r\n case 'image':\r\n this.spotFixHighlightImageElement(element);\r\n break;\r\n\r\n case 'element':\r\n this.spotFixHighlightNestedElement(element);\r\n break;\r\n\r\n case 'text':\r\n this.spotFixHighlightTextInElement(element, spots, widgetInstance);\r\n break;\r\n\r\n default:\r\n spotFixDebugLog('Unknown selection type: ' + selectionType);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Highlight image element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightImageElement(element) {\r\n if (element.tagName !== 'IMG') {\r\n spotFixDebugLog('Expected IMG element for image highlight, got: ' + element.tagName);\r\n return;\r\n }\r\n element.classList.add('doboard_task_widget-image_selection');\r\n}\r\n\r\n/**\r\n * Highlight nested element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightNestedElement(element) {\r\n element.classList.add('doboard_task_widget-element_selection');\r\n}\r\n\r\n/**\r\n * Highlight text in element with span wrapping\r\n * @param {Element} element\r\n * @param {Array} spots\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightTextInElement(element, spots,widgetInstance) {\r\n let tooltipTitleText = '';\r\n if (spots[0].isFixed) {\r\n tooltipTitleText = `This issue already fixed.`;\r\n } else {\r\n tooltipTitleText = `We are already working on this issue.`;\r\n }\r\n\r\n const tooltip = `
\r\n \r\n \r\n
${tooltipTitleText}
\r\n
You can see history Here
\r\n
\r\n
`;\r\n\r\n const spotfixHighlightOpen = `${tooltip}`;\r\n const spotfixHighlightClose = ``;\r\n\r\n let text = element.textContent;\r\n const spotSelectedText = spots[0].selectedText;\r\n\r\n // meta.selectedText can not be empty string\r\n if ( ! spotSelectedText ) {\r\n spotFixDebugLog('Provided metadata is invalid.');\r\n return;\r\n }\r\n\r\n const markers = [];\r\n\r\n // Mark positions for inserting\r\n spots.forEach(spot => {\r\n // Validating positions\r\n const startPos = parseInt(spot.startSelectPosition) || 0;\r\n const endPos = parseInt(spot.endSelectPosition) || 0;\r\n\r\n if (startPos < 0 || endPos > text.length || startPos > endPos) {\r\n spotFixDebugLog('Invalid text positions: ' + spot);\r\n return;\r\n }\r\n\r\n markers.push({ position: startPos, type: 'start' });\r\n markers.push({ position: endPos, type: 'end' });\r\n });\r\n\r\n if (markers.length === 0) return;\r\n\r\n // Sort markers backward\r\n markers.sort((a, b) => b.position - a.position);\r\n\r\n // Check here that element (from meta.nodePath) contains same inner text as in meta.selectedText\r\n // Is the `text` in the element equal to the selected text `spotSelectedText`\r\n if ( text.slice(markers[1].position, markers[0].position) !== spotSelectedText ) {\r\n spotFixDebugLog('It is not allow to highlight element by provided metadata.');\r\n return;\r\n }\r\n\r\n let result = text;\r\n markers.forEach(marker => {\r\n const insertText = marker.type === 'start'\r\n ? spotfixHighlightOpen\r\n : spotfixHighlightClose;\r\n\r\n result = result.slice(0, marker.position) + insertText + result.slice(marker.position);\r\n });\r\n\r\n // Safety HTML insert\r\n try {\r\n element.innerHTML = ksesFilter(result);\r\n document.querySelectorAll('.doboard_task_widget-see-task').forEach(link => {\r\n link.addEventListener('click', (e) => {\r\n\r\n e.preventDefault();\r\n const classList = link.className.split(' ');\r\n const idClass = classList.find(cls => cls.includes('__task-id-'));\r\n let taskId = null;\r\n if (idClass) {\r\n taskId = idClass.split('__task-id-')[1];\r\n }\r\n if (taskId) {\r\n widgetInstance.currentActiveTaskId = taskId;\r\n widgetInstance.showOneTask();\r\n }\r\n });\r\n });\r\n } catch (error) {\r\n spotFixDebugLog('Error updating element content: ' + error);\r\n }\r\n}\r\n\r\n/**\r\n * Scroll to an element by tag, class, and text content\r\n * @param {array} path - The path to the element\r\n * @return {boolean} - True if the element was found and scrolled to, false otherwise\r\n */\r\nfunction spotFixScrollToNodePath(path) {\r\n const node = spotFixRetrieveNodeFromPath(path);\r\n if (node && node.scrollIntoView) {\r\n node.scrollIntoView({ behavior: 'smooth', block: 'center' });\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction spotFixRemoveHighlights() {\r\n const textSelectionclassName = 'doboard_task_widget-text_selection';\r\n const spans = document.querySelectorAll('.' + textSelectionclassName);\r\n const affectedParents = new Set(); // Track unique parents\r\n\r\n spans.forEach(span => {\r\n const parent = span.parentNode;\r\n affectedParents.add(parent); // Mark parent as affected\r\n const tooltip = span.querySelector('.doboard_task_widget-text_selection_tooltip');\r\n if (tooltip) tooltip.remove();\r\n\r\n // Move all child nodes out of the span and into the parent\r\n while (span.firstChild) {\r\n parent.insertBefore(span.firstChild, span);\r\n }\r\n parent.removeChild(span);\r\n });\r\n\r\n // Normalize all affected parents to merge adjacent text nodes\r\n affectedParents.forEach(parent => parent.normalize());\r\n\r\n const elementSelectionClassName = 'doboard_task_widget-element_selection';\r\n const elements = document.querySelectorAll(`.${elementSelectionClassName}`);\r\n elements.forEach(element => {\r\n element.classList.remove(elementSelectionClassName);\r\n });\r\n const imageSelectionClassName = 'doboard_task_widget-image_selection';\r\n const images = document.querySelectorAll(`.${imageSelectionClassName}`);\r\n images.forEach(element => {\r\n element.classList.remove(imageSelectionClassName);\r\n });\r\n}\r\n\r\n/**\r\n * Validate nodePath as array of indices\r\n * @param {Array} nodePath\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsValidNodePath(nodePath) {\r\n if (!Array.isArray(nodePath)) return false;\r\n if (nodePath.length === 0) return false;\r\n\r\n return nodePath.every(index => {\r\n return Number.isInteger(index) && index >= 0 && index < 1000;\r\n });\r\n}\r\n\r\n/**\r\n * Try to find selected image in selection.\r\n * @param selection\r\n * @returns {Node|*|null}\r\n */\r\nfunction spotFixGetSelectedImage(selection) {\r\n\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\r\n return null;\r\n }\r\n\r\n const range = selection.getRangeAt(0);\r\n\r\n // Is current end container IMG\r\n if (range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE &&\r\n range.startContainer.tagName === 'IMG') {\r\n return range.startContainer;\r\n }\r\n\r\n // Get img in the range\r\n const walker = document.createTreeWalker(\r\n range.commonAncestorContainer,\r\n NodeFilter.SHOW_ELEMENT,\r\n {\r\n acceptNode: function(node) {\r\n return node.tagName === 'IMG' &&\r\n spotFixIsElementInRange(node, range) ?\r\n NodeFilter.FILTER_ACCEPT :\r\n NodeFilter.FILTER_REJECT;\r\n }\r\n }\r\n );\r\n\r\n let imgNode = walker.nextNode();\r\n if (imgNode) {\r\n return imgNode;\r\n }\r\n\r\n // start/end containers\r\n const startElement = spotFixGetElementFromNode(range.startContainer);\r\n const endElement = spotFixGetElementFromNode(range.endContainer);\r\n\r\n // If selection starts on image\r\n if (startElement && startElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(startElement, range)) {\r\n return startElement;\r\n }\r\n\r\n if (endElement && endElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(endElement, range)) {\r\n return endElement;\r\n }\r\n\r\n // 4. Get closest IMG\r\n const nearbyElements = spotFixFindNearbyElements(range);\r\n for (const element of nearbyElements) {\r\n if (element.tagName === 'IMG') {\r\n return element;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction spotFixIsElementInRange(element, range) {\r\n const elementRange = document.createRange();\r\n elementRange.selectNode(element);\r\n return range.compareBoundaryPoints(Range.START_TO_START, elementRange) <= 0 &&\r\n range.compareBoundaryPoints(Range.END_TO_END, elementRange) >= 0;\r\n}\r\n\r\nfunction spotFixIsElementPartiallySelected(element, range) {\r\n const elementRect = element.getBoundingClientRect();\r\n const rangeRect = range.getBoundingClientRect();\r\n\r\n // bounding rectangles is crossed\r\n return !(elementRect.right < rangeRect.left ||\r\n elementRect.left > rangeRect.right ||\r\n elementRect.bottom < rangeRect.top ||\r\n elementRect.top > rangeRect.bottom);\r\n}\r\n\r\nfunction spotFixGetElementFromNode(node) {\r\n return node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n}\r\n\r\n/**\r\n * Find nearby elements in the range.\r\n * @param range\r\n * @returns {*[]}\r\n */\r\nfunction spotFixFindNearbyElements(range) {\r\n const elements = [];\r\n const container = range.commonAncestorContainer;\r\n\r\n // search elements\r\n const previousElement = container.previousElementSibling;\r\n const nextElement = container.nextElementSibling;\r\n\r\n if (previousElement) {\r\n elements.push(previousElement);\r\n }\r\n if (nextElement) {\r\n elements.push(nextElement);\r\n }\r\n\r\n // Also check child container\r\n if (container.nodeType === Node.ELEMENT_NODE) {\r\n const children = container.children;\r\n for (let i = 0; i < children.length; i++) {\r\n if (spotFixIsElementPartiallySelected(children[i], range)) {\r\n elements.push(children[i]);\r\n }\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Calculate the path of a DOM node\r\n *\r\n * @param {Node} node\r\n * @return {int[]}\r\n */\r\nfunction spotFixCalculateNodePath(node) {\r\n let path = [];\r\n while (node) {\r\n let index = 0;\r\n let sibling = node.previousSibling;\r\n while (sibling) {\r\n if (sibling.nodeType === 1) {\r\n index++;\r\n }\r\n sibling = sibling.previousSibling;\r\n }\r\n path.unshift(index);\r\n node = node.parentNode;\r\n }\r\n\r\n // Hard fix - need to remove first element to work correctly\r\n path.shift();\r\n\r\n return path;\r\n}\r\n\r\n/**\r\n * Retrieve a DOM node from a path\r\n *\r\n * @param {int[]} path\r\n * @return {*|null}\r\n */\r\nfunction spotFixRetrieveNodeFromPath(path) {\r\n // @ToDo check if the path is correct\r\n if ( ! path ) {\r\n return null;\r\n }\r\n\r\n let node = document;\r\n for (let i = 0; i < path.length; i++) {\r\n node = node.children[path[i]];\r\n if ( ! node ) {\r\n return null;\r\n }\r\n }\r\n return node;\r\n}\r\n\n/**\r\n * Return bool if widget is closed in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetWidgetIsClosed() {\r\n return localStorage.getItem('spotfix_widget_is_closed') === '1';\r\n}\r\n\r\n/**\r\n * Return bool if widget closed state is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageWidgetCloseIsSet() {\r\n return localStorage.getItem('spotfix_widget_is_closed') !== null;\r\n}\r\n\r\n/**\r\n * Save widget closed state\r\n * @param visible\r\n */\r\nfunction storageSetWidgetIsClosed(visible) {\r\n localStorage.setItem('spotfix_widget_is_closed', visible ? '1' : '0');\r\n}\r\n\r\n/**\r\n * Return bool if user is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetUserIsDefined() {\r\n return localStorage.getItem('spotfix_user_id') !== null;\r\n}\r\n\r\n/**\r\n * Save data for updates check\r\n * @param tasks\r\n */\r\nfunction storageSaveTasksUpdateData(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n\r\n tasks.forEach(task => {\r\n if (task.taskId && task.taskLastUpdate) {\r\n storedTasks[task.taskId] = {\r\n taskId: task.taskId,\r\n taskLastUpdate: task.taskLastUpdate\r\n };\r\n }\r\n });\r\n\r\n localStorage.setItem('spotfix_task_updates', JSON.stringify(storedTasks));\r\n}\r\n\r\nfunction storageSaveTasksCount(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n const count = tasks.filter(task => {\r\n return task.taskMeta;\r\n })?.length;\r\n\r\n localStorage.setItem('spotfix_tasks_count', `${count}`);\r\n}\r\n\r\n/**\r\n * Check if a specific task has been updated since last check\r\n * @param taskId\r\n * @param currentLastUpdate\r\n * @returns {boolean|null}\r\n */\r\nfunction storageCheckTaskUpdate(taskId, currentLastUpdate) {\r\n if (!taskId || !currentLastUpdate) {\r\n return null;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n const storedTask = storedTasks[taskId];\r\n\r\n if (!storedTask) {\r\n return false;\r\n }\r\n\r\n const storedUpdate = new Date(storedTask.taskLastUpdate);\r\n const currentUpdate = new Date(currentLastUpdate);\r\n return currentUpdate > storedUpdate;\r\n}\r\n\r\n/**\r\n * Add unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageAddUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n if (!storedUnread.includes(taskId)) {\r\n storedUnread.push(taskId);\r\n }\r\n\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Remove unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageRemoveUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n storedUnread = storedUnread.filter(id => id !== taskId);\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Check if there are any unread updates\r\n * @returns {boolean}\r\n */\r\nfunction storageTasksHasUnreadUpdates() {\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.length > 0;\r\n}\r\n\r\n/**\r\n * Check if a specific task has unread updates\r\n * @param taskId\r\n * @returns {boolean}\r\n */\r\nfunction storageProvidedTaskHasUnreadUpdates(taskId) {\r\n if (!taskId) {\r\n return false;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.includes(taskId.toString());\r\n}\r\n\r\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 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
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 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
\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.com\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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","style","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","closest","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","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","spotFixShowWidget","spotFixIsInsideWidget","node","el","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","display","containerClassesToShow","containers","tasksDetails","lastComment","dt","avatarSrc","authorName","authorDetails","charAt","toUpperCase","isAnyTaskUpdated","updatedtasksIDS","currentStateOfTask","issuerId","storageCheckTaskUpdate","updatedTaskIDs","lastMessage","updatedTaskId","updatedTaskData","storageAddUnreadUpdateForTaskID","isSelectionCorrect","html","options","allowedTags","strong","em","ul","ol","li","p","br","span","blockquote","pre","div","img","label","button","details","summary","allowedAttrs","doc","DOMParser","parseFromString","childNodes","clean","tag","tagName","toLowerCase","link","alt","target","parentNode","insertBefore","textContent","attributes","attr","attrName","startsWith","readyState","sel","isWrapReviewWidgetExists","focusNode","anchorNode","spotFixCSS","SPOTFIX_SELECTION_TYPE_TEXT","SPOTFIX_SELECTION_TYPE_IMG","SPOTFIX_SELECTION_TYPE_ELEMENT","spotFixGetSelectionType","range","getRangeAt","commonAncestor","commonAncestorContainer","spotFixGetSelectedImage","startContainer","endContainer","hasTextContent","isTextNode","TEXT_NODE","isCollapsed","collapsed","rangeCount","selectionType","startSelectPosition","endSelectPosition","commonNode","commonNodeElement","startOffset","endOffset","spotFixCalculateNodePath","imgElement","selectedImage","from","children","indexOf","imageUrl","widgetInstance","elementsMap","Map","spot","spotFixIsValidNodePath","spotFixRetrieveNodeFromPath","has","set","spots","spotFixHighlightImageElement","spotFixHighlightNestedElement","spotFixHighlightTextInElement","tooltipTitleText","spotfixHighlightOpen","text","spotSelectedText","markers","startPos","parseInt","endPos","position","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","container","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","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 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 localStorage.setItem('spotfix_app_version', 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\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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 || '';\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\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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-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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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\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 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
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 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","checkLogInOutButtonsVisible","el","style","display","closest","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","position","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","container","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/handlers.js b/js/src/handlers.js index 4f155e5..60e9e96 100644 --- a/js/src/handlers.js +++ b/js/src/handlers.js @@ -54,8 +54,10 @@ async function getTasksFullDetails(params, tasks, currentActiveTaskId) { async function getUserDetails(params) { const sessionId = localStorage.getItem('spotfix_session_id'); const currentUserId = localStorage.getItem('spotfix_user_id'); - const users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); - return users[0] || {}; + if(currentUserId) { + const users = await getUserDoboard(sessionId, params.projectToken, params.accountId, currentUserId); + return users[0] || {}; + } } async function handleCreateTask(sessionId, taskDetails) { @@ -286,3 +288,15 @@ function setToggleStatus(rootElement){ toggle.checked = true; toggle.addEventListener('click', clickHandler); } + +function checkLogInOutButtonsVisible (){ + if(!localStorage.getItem('spotfix_session_id')) { + const el = document + .getElementById('doboard_task_widget-user_menu-logout_button') + .closest('.doboard_task_widget-user_menu-item'); + if(el) el.style.display = 'none'; + } else { + const el = document.getElementById('doboard_task_widget-user_menu-signlog_button'); + if(el) el.style.display = 'none'; + } +} diff --git a/js/src/loaders/SpotFixTemplatesLoader.js b/js/src/loaders/SpotFixTemplatesLoader.js index c52b8c5..327ba61 100644 --- a/js/src/loaders/SpotFixTemplatesLoader.js +++ b/js/src/loaders/SpotFixTemplatesLoader.js @@ -34,7 +34,7 @@ class SpotFixTemplatesLoader { @@ -234,9 +234,12 @@ class SpotFixTemplatesLoader {
- + {{userName}} {{email}} + + Sign up or Log in +
@@ -258,10 +261,10 @@ class SpotFixTemplatesLoader {
- -
+ + Log out -
+
@@ -269,7 +272,7 @@ class SpotFixTemplatesLoader { {{spotfixVersion}} Powered by - doboard.com + doBoard diff --git a/js/src/widget.js b/js/src/widget.js index 71db9bb..989e237 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -315,7 +315,7 @@ class CleanTalkWidgetDoboard { iconDoor: SpotFixSVGLoader.getAsDataURI('iconDoor'), chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'), buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'), - userName: '', + userName: 'Guest', email: '', ...this.srcVariables}; break; @@ -495,6 +495,8 @@ class CleanTalkWidgetDoboard { case 'user_menu': setToggleStatus(this); + checkLogInOutButtonsVisible(); + const user = await getUserDetails(this.params); const gitHubAppVersion = await getReleaseVersion(); let spotfixVersion = ''; @@ -504,14 +506,15 @@ class CleanTalkWidgetDoboard { templateVariables.spotfixVersion = spotfixVersion || ''; if(user){ - templateVariables.userName = user.name; - templateVariables.email = user.email; + templateVariables.userName = user.name || 'Guest'; + templateVariables.email = user.email || ''; if(user?.avatar?.s) templateVariables.avatar = user?.avatar?.s; } widgetContainer.innerHTML = this.loadTemplate('user_menu', templateVariables); document.body.appendChild(widgetContainer); setToggleStatus(this); + checkLogInOutButtonsVisible(); break; case 'concrete_issue': @@ -704,6 +707,10 @@ class CleanTalkWidgetDoboard { this.createWidgetElement('user_menu') }) || ''; + document.querySelector('#doboard_task_widget-user_menu-signlog_button')?.addEventListener('click', () => { + spotFixShowWidget(); + }) || ''; + document.querySelector('#spotfix_back_button')?.addEventListener('click', () => { this.createWidgetElement(this.type_name) }) || ''; diff --git a/styles/doboard-widget.css b/styles/doboard-widget.css index 197d6fa..8c460ec 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -126,6 +126,15 @@ 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; @@ -1237,3 +1246,4 @@ input:checked + .slider:before { color: #707A83; cursor: pointer; } + From fa4e9d3cf37147b742a326a25ef46cc331d83d71 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Thu, 18 Dec 2025 14:07:41 +0400 Subject: [PATCH 05/20] Fix. Fixed unlimited loading --- dist/doboard-widget-bundle.js | 2 +- dist/doboard-widget-bundle.min.js | 2 +- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/main.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 9a1975f..2195dec 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -1782,7 +1782,7 @@ function hideContainersSpinner() { function getTaskFullDetails(tasksDetails, taskId) { const comments = tasksDetails.comments.filter(comment => { - return comment.taskId.toString() === taskId.toString() + return comment.taskId?.toString() === taskId?.toString() }); const users = tasksDetails.users; // Last comment diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 64ce380..11e919a 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,4 +1,4 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,u=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;i<_.length;i++){var m=_[i],h=m.taskId,w=m.taskTitle,b=m.taskMeta;let t=null;if(b)try{(t=JSON.parse(b)).isFixed="DONE"===m.taskStatus,t.taskId=m.taskId}catch(e){t=null}var k,x,b=t?t.pageURL:"",f=t?t.nodePath:"";let e="",a="Task publicity is unknown";t&&void 0!==t.isPublic&&(a=t.isPublic?(e=this.srcVariables.iconSpotPublic,"The task is public"):(e=this.srcVariables.iconSpotPrivate,"The task is private and visible only for registered DoBoard users")),b===window.location.href&&o++,r&&b!==window.location.href||(x=getAvatarData(k=getTaskFullDetails(n,h)),w={taskTitle:w||"",taskAuthorAvatarImgSrc:k.taskAuthorAvatarImgSrc,taskAuthorName:k.taskAuthorName,taskPublicStatusImgSrc:e,taskPublicStatusHint:a,taskLastMessage:ksesFilter(k.lastMessageText),taskPageUrl:b,iconLinkChain:this.srcVariables.iconLinkChain,taskFormattedPageUrl:spotFixSplitUrl(b),taskLastUpdate:k.lastMessageTime,nodePath:this.sanitizeNodePath(f),taskId:h,avatarCSSClass:x.avatarCSSClass,avatarStyle:x.avatarStyle,taskAuthorInitials:x.taskAuthorInitials,initialsClass:x.initialsClass,classUnread:"",elementBgCSSClass:"DONE"!==m.taskStatus?"":"doboard_task_widget-task_row-green",statusFixedHtml:"DONE"!==m.taskStatus?"":this.loadTemplate("fixedHtml")},storageProvidedTaskHasUnreadUpdates(k.taskId)&&(w.classUnread="unread"),document.querySelector(".doboard_task_widget-all_issues-container").innerHTML+=this.loadTemplate("list_issues",w),this.isSpotHaveToBeHighlighted(t)&&u.push(t))}this.savedIssuesQuantityOnPage=o,this.savedIssuesQuantityAll=g.length,spotFixHighlightElements(u,this),document.querySelector(".doboard_task_widget-header span").innerHTML+=ksesFilter(" "+getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll))}0===g.length&&(document.querySelector(".doboard_task_widget-all_issues-container").innerHTML=ksesFilter('
The issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name||"Guest",l.email=p.email||"",p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId.toString()===t.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,u=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;i<_.length;i++){var m=_[i],h=m.taskId,w=m.taskTitle,b=m.taskMeta;let t=null;if(b)try{(t=JSON.parse(b)).isFixed="DONE"===m.taskStatus,t.taskId=m.taskId}catch(e){t=null}var k,x,b=t?t.pageURL:"",f=t?t.nodePath:"";let e="",a="Task publicity is unknown";t&&void 0!==t.isPublic&&(a=t.isPublic?(e=this.srcVariables.iconSpotPublic,"The task is public"):(e=this.srcVariables.iconSpotPrivate,"The task is private and visible only for registered DoBoard users")),b===window.location.href&&o++,r&&b!==window.location.href||(x=getAvatarData(k=getTaskFullDetails(n,h)),w={taskTitle:w||"",taskAuthorAvatarImgSrc:k.taskAuthorAvatarImgSrc,taskAuthorName:k.taskAuthorName,taskPublicStatusImgSrc:e,taskPublicStatusHint:a,taskLastMessage:ksesFilter(k.lastMessageText),taskPageUrl:b,iconLinkChain:this.srcVariables.iconLinkChain,taskFormattedPageUrl:spotFixSplitUrl(b),taskLastUpdate:k.lastMessageTime,nodePath:this.sanitizeNodePath(f),taskId:h,avatarCSSClass:x.avatarCSSClass,avatarStyle:x.avatarStyle,taskAuthorInitials:x.taskAuthorInitials,initialsClass:x.initialsClass,classUnread:"",elementBgCSSClass:"DONE"!==m.taskStatus?"":"doboard_task_widget-task_row-green",statusFixedHtml:"DONE"!==m.taskStatus?"":this.loadTemplate("fixedHtml")},storageProvidedTaskHasUnreadUpdates(k.taskId)&&(w.classUnread="unread"),document.querySelector(".doboard_task_widget-all_issues-container").innerHTML+=this.loadTemplate("list_issues",w),this.isSpotHaveToBeHighlighted(t)&&u.push(t))}this.savedIssuesQuantityOnPage=o,this.savedIssuesQuantityAll=g.length,spotFixHighlightElements(u,this),document.querySelector(".doboard_task_widget-header span").innerHTML+=ksesFilter(" "+getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll))}0===g.length&&(document.querySelector(".doboard_task_widget-all_issues-container").innerHTML=ksesFilter('
The issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name||"Guest",l.email=p.email||"",p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index d6cf966..b9e91d6 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 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 localStorage.setItem('spotfix_app_version', 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\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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 || '';\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\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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-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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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\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 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
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 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","checkLogInOutButtonsVisible","el","style","display","closest","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","position","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","container","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 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 localStorage.setItem('spotfix_app_version', 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\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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 || '';\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\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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-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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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\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 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
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 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","checkLogInOutButtonsVisible","el","style","display","closest","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","position","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","container","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/main.js b/js/src/main.js index f8c466c..c46206a 100644 --- a/js/src/main.js +++ b/js/src/main.js @@ -120,7 +120,7 @@ function hideContainersSpinner() { function getTaskFullDetails(tasksDetails, taskId) { const comments = tasksDetails.comments.filter(comment => { - return comment.taskId.toString() === taskId.toString() + return comment?.taskId?.toString() === taskId?.toString() }); const users = tasksDetails.users; // Last comment From a6fee5a2f9c88857f2ab1b2895196c6a86679dd2 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Mon, 22 Dec 2025 20:30:57 +0400 Subject: [PATCH 06/20] Upd. Added a method for unlogging --- dist/doboard-widget-bundle.js | 25 +++++++++++++++++++++++-- dist/doboard-widget-bundle.min.js | 4 ++-- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/api.js | 17 +++++++++++++++++ js/src/widget.js | 4 ++++ styles/doboard-widget.css | 11 ++++++++--- 6 files changed, 55 insertions(+), 8 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 2195dec..3b0e1a1 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -185,6 +185,23 @@ const loginUserDoboard = async (email, password) => { } } +const jogoutUserDoboard = async (accountId) => { + const sessionId = localStorage.getItem('spotfix_session_id'); + if(sessionId && accountId) { + const data = { + session_id: sessionId, + }; + + const result = await spotfixApiCall(data, 'user_unauthorize', accountId); + if(result.operation_status === 'SUCCESS') { + localStorage.removeItem('spotfix_email'); + localStorage.removeItem('spotfix_session_id'); + localStorage.removeItem('spotfix_user_id'); + localStorage.setItem('spotfix_widget_is_closed', '1'); + } + } +} + const getTasksDoboard = async (projectToken, sessionId, accountId, projectId, userId) => { const data = { session_id: sessionId, @@ -1309,6 +1326,10 @@ class CleanTalkWidgetDoboard { this.createWidgetElement('user_menu') }) || ''; + document.querySelector('#doboard_task_widget-user_menu-logout_button')?.addEventListener('click', () => { + jogoutUserDoboard(this.params.accountId); + }) || ''; + document.querySelector('#doboard_task_widget-user_menu-signlog_button')?.addEventListener('click', () => { spotFixShowWidget(); }) || ''; @@ -1782,7 +1803,7 @@ function hideContainersSpinner() { function getTaskFullDetails(tasksDetails, taskId) { const comments = tasksDetails.comments.filter(comment => { - return comment.taskId?.toString() === taskId?.toString() + return comment?.taskId?.toString() === taskId?.toString() }); const users = tasksDetails.users; // Last comment @@ -2040,6 +2061,7 @@ function ksesFilter(html, options = false) { return doc.body.innerHTML; } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`; /** * SELECTION will be grouped into three types: * 1 - Simple text within a single tag @@ -2599,7 +2621,6 @@ function spotFixRetrieveNodeFromPath(path) { return node; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 11e919a..0bbbbbc 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,u=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;i<_.length;i++){var m=_[i],h=m.taskId,w=m.taskTitle,b=m.taskMeta;let t=null;if(b)try{(t=JSON.parse(b)).isFixed="DONE"===m.taskStatus,t.taskId=m.taskId}catch(e){t=null}var k,x,b=t?t.pageURL:"",f=t?t.nodePath:"";let e="",a="Task publicity is unknown";t&&void 0!==t.isPublic&&(a=t.isPublic?(e=this.srcVariables.iconSpotPublic,"The task is public"):(e=this.srcVariables.iconSpotPrivate,"The task is private and visible only for registered DoBoard users")),b===window.location.href&&o++,r&&b!==window.location.href||(x=getAvatarData(k=getTaskFullDetails(n,h)),w={taskTitle:w||"",taskAuthorAvatarImgSrc:k.taskAuthorAvatarImgSrc,taskAuthorName:k.taskAuthorName,taskPublicStatusImgSrc:e,taskPublicStatusHint:a,taskLastMessage:ksesFilter(k.lastMessageText),taskPageUrl:b,iconLinkChain:this.srcVariables.iconLinkChain,taskFormattedPageUrl:spotFixSplitUrl(b),taskLastUpdate:k.lastMessageTime,nodePath:this.sanitizeNodePath(f),taskId:h,avatarCSSClass:x.avatarCSSClass,avatarStyle:x.avatarStyle,taskAuthorInitials:x.taskAuthorInitials,initialsClass:x.initialsClass,classUnread:"",elementBgCSSClass:"DONE"!==m.taskStatus?"":"doboard_task_widget-task_row-green",statusFixedHtml:"DONE"!==m.taskStatus?"":this.loadTemplate("fixedHtml")},storageProvidedTaskHasUnreadUpdates(k.taskId)&&(w.classUnread="unread"),document.querySelector(".doboard_task_widget-all_issues-container").innerHTML+=this.loadTemplate("list_issues",w),this.isSpotHaveToBeHighlighted(t)&&u.push(t))}this.savedIssuesQuantityOnPage=o,this.savedIssuesQuantityAll=g.length,spotFixHighlightElements(u,this),document.querySelector(".doboard_task_widget-header span").innerHTML+=ksesFilter(" "+getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll))}0===g.length&&(document.querySelector(".doboard_task_widget-all_issues-container").innerHTML=ksesFilter('
The issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name||"Guest",l.email=p.email||"",p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHN0RXZ0OndoZW49IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNC4wIChNYWNpbnRvc2gpIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuPRTtsAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAL0UExURUdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKGw/wAAAAAAAAAAAAAAAAAAAAAAAAAAAKOy/6Sw/gAAAAAAAAAAAAAAAIKPz6Kw/6Cw/6Kx/6Gw/6Gw/6Gw/6Gv/qCw/6Gw/6i0/6Oy/67D/6Gw/6Gx/6ez/6u9/6Gw/6Kx/6i5/624/6Cy/wAAAJ6r/6Oy/6W1/qCv/4aR1LPE/4eU0o+d3qGw/6Sy/6Ku/6Cv/KGw/6Cu/4WT1KKr/5up9Q8RGhodK7jI/4mY1K27/6Cv/8PW/7LE/6Gw/7nL/1RchUVLbbnN/0pXfBQVHjY5U2Vwm2ZwnyMmNrDB/6e2/629/7XG/6Kw/6Kw/67A/629/3N+vKe3/77Q/52r7HmEtrPE/6Oz8RgaKbTF/7TG/xgaKnaCtsLV/6Sv/7TI/wCv/6Gw/wAAAKCv/6e2/73O/6a1/6Oz/6u7/7zN/6q5/7fJ/629/7PD/wAAAQwNE5+u/7DA/6S0/7bH/7XG/6Gx/6i4/yUoOQQFBwICA7HC/7nL/zM4UouY3RcaJK+//y4ySL7Q/ygsPx8iME9WfTA1TXJ8sp2s9VxkjoSQ0RESGl9ok5up9XR/t213rRQWHkRKbJKf53mEwUxSeKGv+qy8/5Ce4jk+WQkKDjxBYCouQpSh6lZfiEFHZVpijJ6t/GFqmWdxoT5DY4eU1mp0qXiDvHyHxZak5n2KxlFZg8LU/32Kv4mV2ZSj7FBYgJGe50VLbS7TJ5EAAACrdFJOUwAPCsvhFe/y+w0C/fc8LUGd9SWvHnW1BPOTw/7NCbtcyNpxsr+4WVKbIETkCOiij0d96tQGEhCmijeFGGxw0Gp6qZhKxmbeYCtNG9NMgKzX5iduYwXl2GVVAZNEVKrs9opx5j/ZFcMIER77LlsYnDAbbDlLDH3+/v2wIlDxy8E95PP9un2PvJ1Pv2VX9kmOqeG89a2m+efFg2aYq9fPqexM0cHR6vWeMdh9ztTtu0oAAA1/SURBVHja7FxnWBPZGs5SQoAAocMiJEjv0qQEpMhCgAVRUFFEaYq9d7f3vb333u99ZpIAafTQ24Jg13XtfV3b7t1d7/65cyaTBiFMkknbZ94f6DOZnG/eOd/56jmhUEiQIEGCBAkSJEiQIEGCBAkSJEiQIEGCBAkS1o6cUAeH0FVWT8OeBaNg2Vs3D6dlMIZlTlZNJAtwoNHB3xyrJmKLMAgqYYch/9haM49YBximp1AoKcicOMRaOxFfCsXX2omgqhVWUmL1qoUtdpr1L3YV87vOyh1igYxHgZU7RATZiGLRvL8NwRZiuRy+DTwcARFHckYsB6l+MOyXasUEUjwichM8C1bEBcBwQMWKAs+E3AiPQGsLTVwSy1fDcxGQ5FPmYjWhSmA4IwnWgjhGuI0V0HDxj1N/bhrdz49OV79GzXexcBrMF1XefFCCd7ULpyTV0TG1hONS7Z0QqjJTLzItmEZRsvwxVzOyXDWshVjXLEaF/J7kIgulESEPEO0S3FK0WLPoBDvsxkURFkhjTxj2dOURvgvd6xvhid0ctsfSeCRi9jXSFd/9rvkBsm+UWdZ0YGs80mO+O6qaDx5srlK9spKBrXpXC1rkaAoIh2Ro+GxXTX1d7ZbSho2vvLKxoXRLbV19zWY5fR+ZfbaYRe+PPk9M9VwSO9eXboLmYFPp+l9vQ2+ojkG/6m8RNGxkqzxvdgq4rf49DSTk2P5ePeCSmod+OcgCXD0b9R0BL826vKF2uxTSju3HPgBq6Yz6lBJz8/BCfUKhuhVdV1m6EAsUnaXfQRZ9MOp7oszLIwpV8lD1dKOyCcILbhNCBdXNCi+z1kjQWD1P7dqBV6UQfnC5/9lPyUeNhRnrLIGoVkSqXtpbK9WFB9Av4fsUbzDOCvMlKqFzeGzYCOkMLvSvf+aitsus/kNVr9bt5kKQPkz47/yDZj5/wkQDDJULx1/ViwdYKIK//BXEXmbJUaKAA4hR8WSNGyG90Tn8xzeBOzKHEUazj5Uqy0MKGYBOwWEwJcvMFLerhHuVkIH46FMwYq7JFQvNoQjkweUJRsCYplYukIBQlQtkA2QwOiWnboIowbQ8XgYvT5lxv94NEcDko8dg1OUmJVKo9u72bpISQITLE02CANSkKSF4dcq0tknKhYiYEtFXsImdiZ1aaLKbEBoIpPxbIKI3HY9q4LvYioVOFA+I2/u/dmToapMRWaQ6IVs3QYRByv8M1O1MxSNDzd4fI44HMiWjYGxTVe0iEVk+igirm0AiUGvPBDJ4vml4pDggstASlq9XdM4bbUQS4Q7PAE+bYppiNSJqTaDr2kyfGBp8Y4jQGYGE0rPI8MUmIVIOeh9YY639soRLKBGp4Js5VQCjqJVbYohq6+kzvpRQHhBX9AlafU10M2LNbmV2vHpbjVZ4hOAJQXSL24FMNOJOqHnZK41AwtctfYUqB3pheSaz5E8ionlArb03ZETQwkr6El9CabglxKhNRcjL9uim0T9AhBPhCkCC1aEQFZPgRphGJarMRTCDivzFwpNdnYTzgKChM4iAt34arJS5ItGDABrL8xQD+vnkZjiBfZZJ2B7eesgIED5ApuPmCYqrt4+7YqOBp6FZCpMlHyspMnwpuFKsUknbYgwivLbbiIjXwPhLwyMVDW2WIdF9uLxP6x4fLq9n5ioLabuMwQNqFX2MiPgCa2vFRsTL5yU5XE8a0fLmf0GOvXp5cbHsvzuNQgTi30dEfLNTWSnPKZBvMtBn3b+A9SrhNPVvhygTht3GISICqfvIb9SsZhr2MIwXdOWxBGvqMzizPgBvB9tIUmocIhLg2/t/ry6Wg71XuyW68cjFZmNOZrBuDXJZRm7zUeMQ6XqEiBg7unmWZA5mPnUq4aGdF9g2WoOHr0AiE9mSqTEOD0h8ZxCGzz5onLtobeE5fQztiEe/kKnpIyc7Ral5n9QoPDpFj5AAZYy7T4P0TPTB4nXqe1DnUcYg5LMEVMnqjEGEyx3/L8jbp4fqNC5dqg59+XC0Tztf5Jmj2Of+207iaUjH+eIvgISHw7UaxXsU4i59LQW9o9XseTMS1NeyXvKlvC0mmAXE6xl+dv8tMP4lYd+H8/T1wX4v2lIcRICdc9aSCbhhdjDzd72CcQLz3JYhft+X9wZkox8WdZbOF8OCBhNjYR5sMI7W03YR8g2K/aevdwm6eESE8i3j/K4jd6ewgTu+FHChhqp55K+ClfG3FoBO8ZoF4nq5n4UHJ06PXuP3ClsN4MJt7Rvii6+fvo0lU/DAvWfDyMtpmvecBojwFz41ALYhZC+YopQVyrm09598ckrCl7S16EWCJx4WdR++OzkoH2/s7rPhISTPkVbOK32xal1Na8MAx1YwJ2Y5TZGodNy4//l5sUAkFrbgN8lSnnBIIOq7/PDjMcVAgzdmugVdUi5ihX81v2xXXM0HPyQfx3e2wGtxgUr22zHxfOb6VbFgWCIW8lq1B+o8oVgiGG47debTb6YGlENMnr7eK+pDtIrb8O4OLYId6XiODeAnAlTMO5TWrnySwUvTVx4+vXy1TyIQiCRd4jZhH4/Ha2np7m5B/u0TCsVdkh6BQCK8evnJuSu3O1Tew2D/3VGxYBxdbFsqm7VKxUcEp2opUJLzwzcH1SoTA2cnb508/fjJmTunHiAvv+2aeHwc4cRr5Z668+jpxXMnb01eGlD7xs2Rc0euCbpagC9pqtuxkEh8qoVrsavj4Hd/8KNLg3M3wQ90XJrqn5yYmB4ZmZ643T811jGg4ab+KxfODwnGeUDpGtbXrKMseKoM32IH5jdYNyJOFErV/nd+/L3+DlgntJ8deT7zdZugpw31q6V1jVW45OEzvws7xPmweWfdaz+5MjLV0b4wh5tTt54/Hr06zu+5xgOGrmH3vuN45aAOEcfmLjRE4eiZ52/9/qFjb4xeOHfy3nQ/oknq+tY+0DHWP33v5LkLX53nSfiicWGLbM/pvh3N+EVwcIYosqAxzoDNklXbPjj0/i9/8XPo/NejZz7/5MLMxYsXZy48eXpm9M55qEXcyx/u7WrrQ7Rpe8OH6+trtoKUQAfjEoc3aJSF8XaGFpCb9zZWHnr3Z2//+W9/7+3p6e2VSIaA7eprObppY9OW2vX/rmzc26z7sCvRWgLOwpDWxEp3RluP79jfWHPgxIYTBw7U7N9xfGuz/oMtRxOrBAJSXfNCx1RXUXxYYlk0sOKDTq1SrByUZ0HHO/QqB6kU6CzkUIQrVqArjCaqZGoWKEum+hz6dZMXsVlZZj2Mbp/FMqSIPautwDTTwYjYiHi6oW0FzY0eU2Ipk0FMo0fWeguQj+Xuk5uRYioSKXtUW2/lRGwQ9EhMVgZ+MYzsDKNvxg/k5DBUziwHl3kQZjXU2tNJIWXF9r5GIsEuLgtRPbNsl0Cs1ZyzYcDOM5PJIdQC2HCYZWlr1I4nE75hAIs8s+Pj1I9BU1nxmVnRXgYunBS2y9rMeBZVbWh6knG2cMjhqSHdo8WxPP0T1y7fw7bR4Ue0nGzYe5avTfT3ZM16OzJ4GtkggteWXuTPcteUwNKphbZhaf5l3llF4cVuGa4eHlElbHtwDNyeXRLl4eGa4VYcXpTlXeafFmZbSNX0/LAfy78oHUy2cY096OnGoBGMy6rMEDua9sw8wNmZRqO7Ozi4u9NoNOcA7XfTKoLSs1zQti0wLSHG5JGhvpMcbAXMTLOl0mCD4Ey1TcvMUV1qYJMenGFEIos0bma1YWdELE5PC1oW567L87vHLQtKS88Nd4uywSmIMCz0omJTOS7FzKzE9Pz4cp9Q2+TgQruKJCr4ORFqUoVdYXCybahPeXx+emIWs9iFkxqLe+qJhs6q6+SbEsgGP/DCDkzxddJrMRoDoFQJ636AU6+f3PGCcZUT9fO87nqdsNPzR5BAKYdunN9OQoe2MRURR3djHUxEJ3sxxVREKNn/b+dsdhIGojBqoZRCY4QIgokSLUyCJSSQEONGFiILExZKoj4GT8Y7ynRouVBiMr93c09YsOrH7XSmZ4Z2rLxx1SnV+opv1ynvr8Wnp/1ayZw1PsXDsh9UFRtEvZB0bKkGfnkYm2iYj14EbJctXBWyYMCGI6b7tPxzwXavPReFGMg9XonJnr4FZ+exYr+QCnjqN1DMLSjPdjtob7hYh1Ox38ad/UJELptyG33ZtAcquZBluirGn2D0xaB+ma7ZLW0Xkufe7l+CU8mFlDO36uzuTmH6Y26kt1dVKCTPrUVim12VXLgqw3++6GOT8eck/eLtWrt7b7cQmDsaq+bCA3bzA17M9rMeJ4UYyT1t4pN/5p1dWtq5hU73Dva9E53u10ln1809O/xetTyvleyHQckToz786uWevzGFzWa2wvAjeWOq80Lq7nOP8YqqIGsbMz7VnbnPPWXFwGJPyFaSq6xxY84XH+aN+Mtl7nmNf+UaH/gPb7I6vWDwnMqas3ruvxMr+QmOCYNVyTVN3mGj9KNvsFiIIbS3TnYeHiTrnq7BYnEwZ75LuQGDxSI3WP76e6BvsFhAg/0eJQbED6sQ4waLeWkZNVjUzm7UYHGHX4MGi35DNGawWFgwWCwsGCwWVgyWIAiCIAiCIAiCIAiCIAiCIAgU/gAyRDCHjvicJQAAAABJRU5ErkJggg==');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a=new URL(e),i=a.host,o=a.pathname.split("/").filter(Boolean);return 0===o.length?i:((t=o.reverse()).push(i),t.join(" / "))}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,u=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;i<_.length;i++){var m=_[i],h=m.taskId,w=m.taskTitle,b=m.taskMeta;let t=null;if(b)try{(t=JSON.parse(b)).isFixed="DONE"===m.taskStatus,t.taskId=m.taskId}catch(e){t=null}var k,x,b=t?t.pageURL:"",f=t?t.nodePath:"";let e="",a="Task publicity is unknown";t&&void 0!==t.isPublic&&(a=t.isPublic?(e=this.srcVariables.iconSpotPublic,"The task is public"):(e=this.srcVariables.iconSpotPrivate,"The task is private and visible only for registered DoBoard users")),b===window.location.href&&o++,r&&b!==window.location.href||(x=getAvatarData(k=getTaskFullDetails(n,h)),w={taskTitle:w||"",taskAuthorAvatarImgSrc:k.taskAuthorAvatarImgSrc,taskAuthorName:k.taskAuthorName,taskPublicStatusImgSrc:e,taskPublicStatusHint:a,taskLastMessage:ksesFilter(k.lastMessageText),taskPageUrl:b,iconLinkChain:this.srcVariables.iconLinkChain,taskFormattedPageUrl:spotFixSplitUrl(b),taskLastUpdate:k.lastMessageTime,nodePath:this.sanitizeNodePath(f),taskId:h,avatarCSSClass:x.avatarCSSClass,avatarStyle:x.avatarStyle,taskAuthorInitials:x.taskAuthorInitials,initialsClass:x.initialsClass,classUnread:"",elementBgCSSClass:"DONE"!==m.taskStatus?"":"doboard_task_widget-task_row-green",statusFixedHtml:"DONE"!==m.taskStatus?"":this.loadTemplate("fixedHtml")},storageProvidedTaskHasUnreadUpdates(k.taskId)&&(w.classUnread="unread"),document.querySelector(".doboard_task_widget-all_issues-container").innerHTML+=this.loadTemplate("list_issues",w),this.isSpotHaveToBeHighlighted(t)&&u.push(t))}this.savedIssuesQuantityOnPage=o,this.savedIssuesQuantityAll=g.length,spotFixHighlightElements(u,this),document.querySelector(".doboard_task_widget-header span").innerHTML+=ksesFilter(" "+getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll))}0===g.length&&(document.querySelector(".doboard_task_widget-all_issues-container").innerHTML=ksesFilter('
The issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name||"Guest",l.email=p.email||"",p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let spotFixCSS=`.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`,SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index b9e91d6..7c16bd1 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 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 localStorage.setItem('spotfix_app_version', 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\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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 || '';\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\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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-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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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\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 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
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 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","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","setItem","err","confirmUserEmail","pendingTaskRaw","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","checkLogInOutButtonsVisible","el","style","display","closest","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","position","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","container","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":"AAAA,IAAMA,gBAAkB,0BAWlBC,eAAiBC,MAAMC,EAAMC,EAAQC,EAAYC,KAAAA,KACnD,GAAI,CAACH,GAAwB,UAAhB,OAAOA,EAChB,MAAM,IAAII,MAAM,6BAA6B,EAGjD,GAAI,CAACH,GAA4B,UAAlB,OAAOA,EAClB,MAAM,IAAIG,MAAM,+BAA+B,EAGnD,GAAkBD,KAAAA,IAAdD,GAAiD,UAArB,OAAOA,GAA+C,UAArB,OAAOA,EACpE,MAAM,IAAIE,MAAM,sCAAsC,EAG1D,IACWC,EADLC,EAAW,IAAIC,SACrB,IAAWF,KAAOL,EACVA,EAAKQ,eAAeH,CAAG,GACnBL,MAAAA,EAAKK,IACLC,EAASG,OAAOJ,EAAKL,EAAKK,EAAI,EAK1CK,IAAIC,EAEAA,EADcR,KAAAA,IAAdD,EACiBL,oBAAmBK,KAAaD,EAEhCJ,gBAAH,IAAsBI,EAGxC,IACI,IAAIW,IAAID,CAAW,CAGvB,CAFE,MAAOE,GACL,MAAM,IAAIT,MAAM,yBAAyBO,CAAa,CAC1D,CAEAD,IAAII,EACJ,IACIA,EAAWC,MAAMC,MAAML,EAAa,CAChCV,OAAQ,OACRgB,KAAMX,CACV,CAAC,CAGL,CAFE,MAAOY,GACL,MAAM,IAAId,MAAM,kBAAkBc,EAAaC,OAAS,CAC5D,CAEAT,IAAIU,EACJ,IACIA,EAAeL,MAAMD,EAASO,KAAK,CAGvC,CAFE,MAAOC,GACL,MAAM,IAAIlB,MAAM,2CAA2C,CAC/D,CAEA,GAAI,CAACgB,GAAwC,UAAxB,OAAOA,EACxB,MAAM,IAAIhB,MAAM,qCAAqC,EAGzD,GAAI,CAACgB,EAAapB,KACd,MAAM,IAAII,MAAM,uCAAuC,EAG3D,GAAI,CAACgB,EAAapB,KAAKuB,iBACnB,MAAM,IAAInB,MAAM,2CAA2C,EAG/D,GAA2C,WAAvCgB,EAAapB,KAAKuB,iBAElB,MADMC,EAAeJ,EAAapB,KAAKyB,mBAAqB,4CACtD,IAAIrB,MAAMoB,CAAY,EAGhC,GAA2C,YAAvCJ,EAAapB,KAAKuB,iBAClB,OAAOH,EAAapB,KAGxB,MAAM,IAAII,MAAM,6BAA6BgB,EAAapB,KAAKuB,gBAAkB,CACrF,EAEMG,wBAA0B3B,MAAO4B,IAC7B3B,EAAO,CACT4B,yBAA0BC,mBAAmBF,CAAsB,CACvE,EACMG,EAASf,MAAMjB,eAAeE,EAAM,oBAAoB,EAC9D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdC,SAAUN,EAAOM,SACjBC,gBAAiBP,EAAOP,gBAC5B,CACJ,EAEMe,kBAAoBvC,MAAOgC,EAAWQ,KACxC,IAAMrC,EAAYqC,EAAYrC,UACxBF,EAAO,CACTgC,WAAYD,EACZS,cAAeD,EAAYE,aAC3BC,WAAYH,EAAYI,UACxBT,QAASU,aAAaC,QAAQ,iBAAiB,EAC/CC,KAAMP,EAAYQ,UAClBC,QAAST,EAAYU,gBACrBC,KAAMX,EAAYY,SAClBC,UAAW,QACf,EAEA,MAAO,CACHC,QAFWtC,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,GAE5CoD,OACnB,CACJ,EAEMC,yBAA2BxD,MAAOG,EAAW6B,EAAWsB,EAAQL,EAASP,EAAce,EAAS,YAC5FxD,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfa,QAASD,EACTL,QAASA,EACTQ,OAAQA,CACZ,EAEA,MAAO,CACHC,WAFW1C,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,GAE5CwD,UACtB,CACJ,EAEMC,qBAAuB5D,MAAO6D,IAChC,IAAM1D,EAAY0D,EAASC,OAAO3D,UAC5BF,EAAO,CACTgC,WAAY4B,EAAS7B,UACrBS,cAAeoB,EAASC,OAAOpB,aAC/BqB,WAAYF,EAASC,OAAO3D,UAC5BwD,WAAYE,EAASH,UACrBM,SAAUH,EAASI,SACnBC,KAAML,EAASM,WACfC,iBAAkBP,EAASQ,eAC/B,EACerD,MAAMjB,eAAeE,EAAM,iBAAkBE,CAAS,CAEzE,EAEMmE,oBAAsBtE,MAAO0C,EAAcvC,EAAWiC,EAAOmC,EAAUC,KACrEvE,EAAO,CACPwC,cAAeC,EACfqB,WAAY5D,EACZsE,iBAAkBrC,CACtB,EACIA,GAASmC,IACTtE,EAAKmC,MAAQA,EACbnC,EAAK8C,KAAOwB,GAEVxC,EAASf,MAAMjB,eAAeE,EAAM,mBAAmB,EAC7D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdsC,cAA+C,IAAhC3C,EAAO4C,qBACtBC,iBAAkB7C,EAAOL,kBACzBY,gBAAiBP,EAAOP,iBACxBqD,mBAAoB9C,EAAO4C,oBAC/B,CACJ,EAEMG,iBAAmB9E,MAAOoC,EAAO2C,KAC7B9E,EAAO,CACTmC,MAAOA,EACP2C,SAAUA,CACd,EACMhD,EAASf,MAAMjB,eAAeE,EAAM,gBAAgB,EAC1D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdsC,cAA+C,IAAhC3C,EAAO4C,qBACtBC,iBAAkB7C,EAAOL,kBACzBY,gBAAiBP,EAAOP,iBACxBqD,mBAAoB9C,EAAO4C,oBAC/B,CACJ,EAEMK,gBAAkBhF,MAAO0C,EAAcV,EAAW7B,EAAWyC,EAAWV,KACpEjC,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfC,WAAYC,EACZS,UAAW,QACf,EACKnB,IACDjC,EAAKkC,QAAUD,GAGb+C,GADSjE,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,GAC1C8E,MAAMC,IAAIC,IAAQ,CACnC7B,OAAQ6B,EAAK5B,QACbP,UAAWmC,EAAKpC,KAChBqC,eAAgBD,EAAKE,QACrBC,YAAaH,EAAKI,QAClBC,oBAAqBL,EAAKM,gBAC1BrC,SAAU+B,EAAKhC,KACfuC,WAAYP,EAAK1B,MACpB,EAAC,EAIF,OAFAkC,sBAAsBV,CAAK,EAEpBA,CACX,EAGMW,wBAA0B5F,MAAOgC,EAAW7B,EAAWuC,EAAce,EAAS,YAC1ExD,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfe,OAAQA,CACZ,EAEA,OADezC,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,GACpD0F,SAASX,IAAIjC,IAAW,CAClCK,OAAQL,EAAQM,QAChBG,UAAWT,EAAQU,WACnBzB,OAAQe,EAAQd,QAChB2D,YAAa7C,EAAQA,QACrB8C,YAAa9C,EAAQoC,QACrB5B,OAAQR,EAAQQ,OAChBuC,WAAY/C,EAAQgD,SACvB,EAAC,CACN,EAEMC,eAAiBlG,MAAOgC,EAAWU,EAAcvC,EAAW+B,KACxDjC,EAAO,CACTgC,WAAYD,EACZS,cAAeC,CACnB,EACIR,IAAQjC,EAAKkC,QAAUD,GAErBH,EAASf,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,EAC/D,OAAO4B,EAAOoE,KA2BlB,EAEMC,kBAAoBpG,MAAO0C,EAAcvC,EAAW6B,EAAWE,EAAQmE,KACnEpG,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfP,QAASD,EACToE,UAAWD,CACf,EAEA,OADArF,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,EAC5C,CACHoG,QAAS,CAAA,CACb,CACJ,EAEMC,kBAAoBxG,UACtB,IACI,IACMC,EAAOe,MADDA,MAAMC,MAAM,yDAAyD,GAC1DK,KAAK,EAE5B,OAAkB,EAAdrB,EAAKwG,QAAcxG,EAAK,GAAGyG,UAC3B7D,aAAa8D,QAAQ,sBAAuB1G,EAAK,GAAGyG,QAAQ,EACrDzG,EAAK,GAAGyG,UAGZ,IAGX,CAFE,MAAOE,GACL,OAAO,IACX,CACJ,EAGA5G,eAAe6G,iBAAiBjF,EAAwBkC,GACvD,IAAM/B,EAASf,MAAMW,wBAAwBC,CAAsB,EAO7DkF,GALNjE,aAAa8D,QAAQ,gBAAiB5E,EAAOK,KAAK,EAClDS,aAAa8D,QAAQ,qBAAsB5E,EAAOC,SAAS,EAC3Da,aAAa8D,QAAQ,kBAAmB5E,EAAOG,MAAM,EAG9BW,aAAaC,QAAQ,sBAAsB,GAClE,GAAI,CAACgE,EAAgB,MAAM,IAAIzG,MAAM,sBAAsB,EAE3DM,IAAIoG,EACJ,IACCA,EAAcC,KAAKC,MAAMH,CAAc,CAGxC,CAFE,MAAOhG,GACR,MAAM,IAAIT,MAAM,2BAA2B,CAC5C,CAGMmC,EAAc,CACnBQ,UAAW+D,EAAYG,cAAgB,WACvChE,gBAAiB6D,EAAYI,aAAe,GAC5CC,aAAcL,EACdrE,aAAcoB,EAAOpB,aACrBE,UAAWkB,EAAOlB,UAClBzC,UAAW2D,EAAO3D,UAClBiD,SAAU4D,KAAKK,UAAUN,CAAW,CACrC,EAGMO,EAActG,MAAMuG,iBAAiBxF,EAAOC,UAAWQ,CAAW,EAKxE,OAHAK,aAAa2E,WAAW,sBAAsB,EAGvCF,CACR,CAEAtH,eAAeyH,oBAAoB3D,EAAQmB,EAAOyC,GAC9C,IACU1F,EADV,GAAmB,EAAfiD,EAAMwB,OAMN,OALMzE,EAAYa,aAAaC,QAAQ,oBAAoB,EAKpD,CACH+C,SALa7E,MAAM4E,wBAAwB5D,EAAW8B,EAAO3D,UAAW2D,EAAOpB,YAAY,EAM3FyD,MALUnF,MAAMkF,eAAelE,EAAW8B,EAAOpB,aAAcoB,EAAO3D,SAAS,EAMxFuF,WALiBT,EAAM0C,KAAKC,GAAQ,CAACA,EAAKtE,QAAW,CAACoE,CAAmB,GAKlDhC,UAClB,CAER,CAEA1F,eAAe6H,eAAe/D,GAC5B,IAAM9B,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDgF,EAAgBjF,aAAaC,QAAQ,iBAAiB,EAC5D,GAAGgF,EAEF,OADc9G,MAAMkF,eAAelE,EAAW8B,EAAOpB,aAAcoB,EAAO3D,UAAW2H,CAAa,GACrF,IAAM,EAEtB,CAEA9H,eAAeuH,iBAAiBvF,EAAWQ,GAC1C,IACC,IAEgBuF,EAFVhG,EAASf,MAAMuB,kBAAkBP,EAAWQ,CAAW,EAQ7D,OAPIT,GAAUA,EAAOuB,QAAUd,EAAYU,kBAC3B6E,4EAAiFC,OAAOC,SAASC,iDAAiDF,OAAOC,SAASC,uBACjLlH,MAAMmH,eAAe,CACpBzF,aAAcF,EAAYE,aAC1BvC,UAAWqC,EAAYrC,SACxB,EAAG4B,EAAOuB,OAAQd,EAAYU,gBAAgB6E,CAAI,GAE5ChG,CAGR,CAFE,MAAO6E,GACR,MAAMA,CACP,CACD,CAEA5G,eAAemI,eAAerE,EAAQR,EAAQ8E,GAC7C,IAAMpG,EAAYa,aAAaC,QAAQ,oBAAoB,EAC3D,GAAI,CAACd,EAAW,MAAM,IAAI3B,MAAM,YAAY,EAC5C,GAAKyD,EAAOpB,cAAiBoB,EAAO3D,UACpC,OAAaqD,yBAAyBM,EAAO3D,UAAW6B,EAAWsB,EAAQ8E,EAAatE,EAAOpB,YAAY,EAD5D,MAAM,IAAIrC,MAAM,gBAAgB,CAEhF,CAEA,SAASgI,aAAavE,GACrB,IAGMpB,EACAV,EACAE,EALN,OAAKW,aAAaC,QAAQ,oBAAoB,GAGxCJ,EAAeoB,EAAOpB,aACtBV,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDZ,EAASW,aAAaC,QAAQ,iBAAiB,EAC9CkC,gBAAgBtC,EAAcV,EAAW8B,EAAO3D,UAAW2D,EAAOlB,UAAWV,CAAM,GALlF,EAMT,CAEAlC,eAAesI,YAAYxE,GAC1B,IAGMpB,EACAV,EAJN,OAAKa,aAAaC,QAAQ,oBAAoB,GAGxCJ,EAAeoB,EAAOpB,aACtBV,EAAYa,aAAaC,QAAQ,oBAAoB,GACzC9B,MAAMgE,gBAAgBtC,EAAcV,EAAW8B,EAAO3D,UAAW2D,EAAOlB,SAAS,GAG/D2F,OAAOpD,GAC7BA,EAAK/B,QACf,GATI,EAYT,CAEA,SAASoF,WAAWC,GAMlB,GAAI,CAACA,EAAS,MAAO,CAAEC,KAAM,GAAIC,KAAM,EAAG,EAC1ChI,IAAIiI,EAQJ,OANCA,EADGH,CAAAA,EAAQI,SAAS,GAAG,GAEbJ,EAAQI,SAAS,GAAG,EACpB,IAAIC,KAAKL,EAAQM,QAAQ,IAAK,GAAG,CAAC,EAElC,IAAID,KAAKL,CAAO,EAEvBO,MAAMJ,EAAQK,QAAQ,CAAC,EAAU,CAAEP,KAAM,GAAIC,KAAM,EAAG,GAGpDO,EAAgBN,EAAQO,kBAAkB,EASzC,CAAET,KA1BM,CACd,UAAW,WAAY,QAAS,QAAS,MAAO,OAChD,OAAQ,SAAU,YAAa,UAAW,WAAY,aAgBnDU,EAAe,IAAIN,KAAKF,EAAQK,QAAQ,EAAoB,IAAhBC,CAAqB,GAEnCG,SAAS,GAE9B,IADDD,EAAaE,QAAQ,EAKlBX,KAHDS,EAAaG,SAAS,EAAEC,SAAS,EAAEC,SAAS,EAAG,GAAG,EAEnD,IADGL,EAAaM,WAAW,EAAEF,SAAS,EAAEC,SAAS,EAAG,GAAG,CAEhD,EACtB,CAEA,SAASE,qBAAqB7F,EAAQR,GACnBT,aAAaC,QAAQ,oBAAoB,EAA3D,IAiBM7C,EAfL,CACC,CACCqD,OAAU,IACVsG,uBAA0B,uGAC1BC,eAAkB,oCACnB,GAUyBlC,KAAK,GAAamC,EAAQxG,SAAWA,CAAM,EACtE,OAAgBlD,KAAAA,IAATH,EAPN,CACCqD,OAAU,KACVsG,uBAA0B,KAC1BC,eAAkB,aACnB,EAGyC5J,CAC3C,CAEA,SAAS8J,uBAAuBC,EAAkBC,GACjD,WAAYD,KAAoBC,IACjC,CAGA,SAASC,aAAaC,GACrB,GAAIA,GAAUA,EAAOC,OAAQ,CAC5B,GAA6B,UAAzB,OAAOD,EAAOC,QAAuBD,EAAOC,OAAOC,EACtD,OAAOF,EAAOC,OAAOC,EACf,GAA6B,UAAzB,OAAOF,EAAOC,OACxB,OAAOD,EAAOC,MAEhB,CACA,OAAO,IACR,CAGA,SAASE,cAAcH,GACtB,GAAIA,EAAQ,CACX,GAAIA,EAAOpH,MAAoC,EAA5BoH,EAAOpH,KAAKwH,KAAK,EAAE9D,OACrC,OAAO0D,EAAOpH,KACR,GAAIoH,EAAO/H,OAAsC,EAA7B+H,EAAO/H,MAAMmI,KAAK,EAAE9D,OAC9C,OAAO0D,EAAO/H,KAEhB,CACA,MAAO,gBACR,CAEA,SAASoI,aAAahI,GACrB,IAAMiI,EAAYjI,EAAYiI,UACxBC,EAAWlI,EAAYkI,SACvBhI,EAAeF,EAAYE,aAC3BvC,EAAYqC,EAAYrC,UACxBqE,EAAUhC,EAAY4E,aAAa5C,SAA6CwD,OAAOC,SAASC,KA4BrG,OA1B0B,GAAyB5D,oBAAoB5B,EAAcvC,EAAWsK,EAAWC,EAAUlG,CAAO,EAC3HmG,KAAK5J,IACL,GAAIA,EAAS2D,cACZkG,SAASC,cAAc,qEAAqE,EAAEC,UAAYC,WAAW,2DAA2D,EAChLH,SAASC,cAAc,4EAA4E,EAAEG,UAAUC,OAAO,QAAQ,EAC9HL,SAASM,eAAe,mCAAmC,EAAEC,MAAM,OAC7D,GAAIpK,EAASiB,UACnBa,aAAa8D,QAAQ,qBAAsB5F,EAASiB,SAAS,EAC7Da,aAAa8D,QAAQ,kBAAmB5F,EAASmB,MAAM,EACvDW,aAAa8D,QAAQ,gBAAiB5F,EAASqB,KAAK,EACpDgJ,WAAW1I,EAAcvC,CAAS,MAC5B,CAAA,GAAIY,EAA6B,YAA7BA,EAASuB,iBAAiCvB,EAAS6D,kBAAuD,EAAnC7D,EAAS6D,iBAAiB6B,QAQ3G,MAAM,IAAIpG,MAAM,kCAAkC,EAPjB,kCAA7BU,EAAS6D,mBACZ7D,EAAS6D,iBAAmB,+DAEM,YAA/B,OAAOyG,GACVA,EAAoBtK,EAAS6D,iBAAkB,QAAQ,CAIzD,CACD,CAAC,EACA0G,MAAMxK,IACN,MAAMA,CACP,CAAC,CAGH,CAEA,SAASyK,UAAU/I,GAClB,IAAMiI,EAAYjI,EAAYiI,UACxBe,EAAehJ,EAAYgJ,aAEjC,OAAO,GAAyB1G,iBAAiB2F,EAAWe,CAAY,EACtEb,KAAK5J,IACL,GAAIA,EAASiB,UACZa,aAAa8D,QAAQ,qBAAsB5F,EAASiB,SAAS,EAC7Da,aAAa8D,QAAQ,kBAAmB5F,EAASmB,MAAM,EACvDW,aAAa8D,QAAQ,gBAAiB5F,EAASqB,KAAK,MAC7C,CAAA,GAAIrB,EAA6B,YAA7BA,EAASuB,iBAAiCvB,EAAS6D,kBAAuD,EAAnC7D,EAAS6D,iBAAiB6B,QAK5G,MAAM,IAAIpG,MAAM,kCAAkC,EAJf,YAA/B,OAAOgL,GACVA,EAAoBtK,EAAS6D,iBAAkB,QAAQ,CAIzD,CACD,CAAC,EACA0G,MAAMxK,IACN,MAAMA,CACP,CAAC,CACH,CAEA,SAASsK,WAAW1I,EAAcvC,GACjC,IAAM6B,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDZ,EAASW,aAAaC,QAAQ,iBAAiB,EAC/CuD,EAAWoF,KAAKC,eAAe,EAAEC,gBAAgB,EAAEC,SAEzD,OAAOxF,kBAAkB1D,EAAcvC,EAAW6B,EAAWE,EAAQmE,CAAQ,CAC9E,CAEA,SAASwF,gBAAgBC,GACxB,IACC,IASMC,EATAC,EAAI,IAAInL,IAAIiL,CAAG,EACfG,EAASD,EAAEE,KAEXC,EAAWH,EAAEI,SAASC,MAAM,GAAG,EAAE9D,OAAO+D,OAAO,EAErD,OAAwB,IAApBH,EAAS1F,OACLwF,IAGFF,EAAWI,EAASI,QAAQ,GACzBC,KAAKP,CAAM,EACbF,EAASU,KAAK,KAAK,EAG3B,CAFE,MAAO3L,GACR,MAAO,EACR,CAED,CAEA,SAAS4L,gBAAgBC,GACxB,IAOMC,EAAShC,SAASM,eAAe,mBAAmB,EAC1D0B,EAAOC,QAAU,CAAA,EACjBD,EAAOE,iBAAiB,QATH,KACpB,IAAMC,EAAQC,WAAW,KACxBnK,aAAa8D,QAAQ,2BAA4B,GAAG,EACpDgG,EAAYM,KAAK,EACjBC,aAAaH,CAAK,CACnB,EAAG,GAAG,CACP,CAG6C,CAC9C,CAEA,SAASI,8BACR,IACOC,EADHvK,aAAaC,QAAQ,oBAAoB,GAMtCsK,EAAKxC,SAASM,eAAe,8CAA8C,KAC1EkC,EAAGC,MAAMC,QAAU,SANpBF,EAAKxC,SACTM,eAAe,6CAA6C,EAC5DqC,QAAQ,qCAAqC,KACvCH,EAAGC,MAAMC,QAAU,OAK7B,OAKME,uBACFtG,aAAe,GACfE,aAAe,GACfqG,cAAgB,KAChB3J,OAAS,GACT4D,oBAAsB,EACtBgG,0BAA4B,EAC5BC,uBAAyB,EACzBC,aAAe,GACfC,aAAe,GAKfC,YAAY1G,EAAc2G,GACtBC,KAAK5G,aAAeA,GAAgB,GACpC4G,KAAK9G,aAAeE,GAAcF,cAAgB,GAClD8G,KAAKC,KAAKF,CAAI,EACdC,KAAKH,aAAe,CAChBK,kBAAmBC,iBAAiBC,aAAa,mBAAmB,EACpEC,iBAAkBF,iBAAiBC,aAAa,kBAAkB,EAClEE,YAAaH,iBAAiBC,aAAa,aAAa,EACxDG,gBAAiBJ,iBAAiBC,aAAa,iBAAiB,EAChEI,kBAAmBL,iBAAiBC,aAAa,mBAAmB,EACpEK,iBAAkBN,iBAAiBC,aAAa,kBAAkB,EAClEM,gBAAiBP,iBAAiBC,aAAa,iBAAiB,EAChEO,yBAA0BR,iBAAiBC,aAAa,0BAA0B,EAClFQ,eAAgBT,iBAAiBC,aAAa,gBAAgB,EAC9DS,gBAAiBV,iBAAiBC,aAAa,iBAAiB,EAChEU,cAAeX,iBAAiBC,aAAa,eAAe,CAChE,EACAJ,KAAKe,aAAe,IAAIC,aAAahB,KAAKiB,UAAU,CACxD,CAKAhB,WAAWF,GACPC,KAAKlK,OAASkK,KAAKkB,UAAU,EAG7B,IAAMC,EAAY,IAAIC,gBAAgBpH,OAAOC,SAASoH,MAAM,EACtDC,EAAaH,EAAUI,IAAI,0BAA0B,EAC3D,GAAID,EACA,IAEI,IAAMhI,EAActG,MAAM6F,iBAAiByI,EAAYtB,KAAKlK,MAAM,EAQ5D0L,GAPNxB,KAAKJ,aAAe5M,MAAMsH,YAAY0F,KAAKlK,MAAM,EAEjDkK,KAAKtG,oBAAsBJ,EAAYhE,OAEvCmM,yBAAyB,EADzB1B,EAAO,iBACuB,EAE9BoB,EAAUO,OAAO,0BAA0B,EAC5B1H,OAAOC,SAASmE,UAAY+C,EAAU3F,SAAS,EAAI,IAAM2F,EAAU3F,SAAS,EAAI,KAC/FxB,OAAO2H,QAAQC,aAAa,GAAIhF,SAASiF,MAAOL,CAAM,CAG1D,CAFE,MAAO5I,GACLoH,KAAK8B,wBAAwB,2BAA6BlJ,EAAIxF,QAAS,OAAO,CAClF,KACG,CAEG2O,EAAiBlN,aAAaC,QAAQ,0BAA0B,GAClEiN,CAAAA,GAAmB/B,KAAK9G,eAAkB6I,IAC1C/B,KAAKJ,aAAe5M,MAAMsH,YAAY0F,KAAKlK,MAAM,EAEzD,CAGAnD,IAAIqP,EAEAC,6BAA6B,EAC7BD,EAAyB,CAAA,EAEZ,gBAATjC,IACAiC,EAAyBhP,MAAMkP,gCAC3BlC,KAAKJ,aACLI,KAAKlK,MACT,GAGRqM,2BAA2BnC,KAAKJ,YAAY,EAEvCwC,wBAAwB,GACzBX,yBAAyB,CAAA,CAAI,EAG7BO,GAEAP,yBAAyB,CAAA,CAAK,EAElCzB,KAAKP,cAAgBzM,MAAMgN,KAAKqC,oBAAoBtC,CAAI,EACxDC,KAAKsC,4BAA4B,CACrC,CAEApB,YACI,IAAMqB,EAAS3F,SAASC,cAAc,uCAAuC,EAC7E,GAAK,CAAE0F,GAAU,CAAEA,EAAOC,IACtB,MAAM,IAAInQ,MAAM,qBAAqB,EAGnCyL,EAAM,IAAIjL,IAAI0P,EAAOC,GAAG,EAC1B1M,EAAS2M,OAAOC,YAAY5E,EAAI6E,aAAaC,QAAQ,CAAC,EAC1D,GAAK,CAAE9M,EACH,MAAM,IAAIzD,MAAM,4BAA4B,EAEhD,GAAOyD,EAAOpB,cAAkBoB,EAAO3D,WAAe2D,EAAOlB,UAI7D,OAAOkB,EAHH,MAAM,IAAIzD,MAAM,sCAAsC,CAI9D,CAKAwQ,uBACI,IAAMC,EAAelG,SAASM,eAAe,mCAAmC,EAE5E4F,GACAA,EAAahE,iBAAiB,QAAS9M,UAEnC,IAAM+Q,EAAmBnG,SAASM,eAAe,2BAA2B,EACtElI,EAAY+N,EAAiBC,MACnC,GAAOhO,EAAP,CAQA,IAAMiO,EAAyBrG,SAASM,eAAe,iCAAiC,EAClFhI,EAAkB+N,EAAuBD,MAC/C,GAAO9N,EAAP,CAUAvC,IAAI+J,EAAW,GACXD,EAAY,GACZe,EAAe,GACnB,IAAM0F,EAAsBtG,SAASC,cAAc,4BAA4B,EAE/E,GAAKqG,GAAuBA,EAAoBlG,UAAUmG,SAAS,QAAQ,EAAI,CAC3E,IAAMC,EAAmBxG,SAASM,eAAe,gCAAgC,EACjF,IAAMmG,EAAkBzG,SAASM,eAAe,+BAA+B,EACzEoG,EAAsB1G,SAASM,eAAe,mCAAmC,EAGvF,GAAK,EADLT,EAAY2G,EAAiBJ,OAOzB,OALAI,EAAiB/D,MAAMkE,YAAc,MACrCH,EAAiBjG,MAAM,EADvBiG,KAEAA,EAAiBtE,iBAAiB,QAAS,WACvCkB,KAAKX,MAAMkE,YAAc,EAC7B,CAAC,EAKL,GAAKH,GAAoBC,GAEhB,EADL3G,EAAW2G,EAAgBL,OAOvB,OALAK,EAAgBhE,MAAMkE,YAAc,MACpCF,EAAgBlG,MAAM,EADtBkG,KAEAA,EAAgBvE,iBAAiB,QAAS,WACtCkB,KAAKX,MAAMkE,YAAc,EAC7B,CAAC,EAMT,GAAKH,GAAoBE,GAAuB,CAAED,GAEzC,EADL7F,EAAe8F,EAAoBN,OAO/B,OALAM,EAAoBjE,MAAMkE,YAAc,MACxCD,EAAoBnG,MAAM,EAD1BmG,KAEAA,EAAoBxE,iBAAiB,QAAS,WAC1CkB,KAAKX,MAAMkE,YAAc,EAC7B,CAAC,CAKb,CAGA,IAAMH,EAAmBxG,SAASM,eAAe,gCAAgC,EACjFT,EAAY2G,EAAiBJ,MAGvBF,EAAelG,SAASM,eAAe,mCAAmC,EAI5E1I,GAHJsO,EAAaU,SAAW,CAAA,EACxBV,EAAahG,UAAYC,WAAW,kBAAkB,EAEpC,CACd/H,UAAWA,EACXE,gBAAiBA,EAEjBkE,aAAc4G,KAAK5G,aACnB1E,aAAcsL,KAAKlK,OAAOpB,aAC1BE,UAAWoL,KAAKlK,OAAOlB,UACvBzC,UAAW6N,KAAKlK,OAAO3D,UACvBiD,SAAU4D,KAAKK,UAAU2G,KAAK5G,YAAY,CAC9C,GACKqD,IACDjI,EAAYiI,UAAYA,GAEvBC,IACDlI,EAAYkI,SAAWA,GAEtBc,IACDhJ,EAAYgJ,aAAeA,GAI/B3I,aAAa8D,QAAQ,uBAAwBK,KAAKK,UAAU,CACxD,GAAG2G,KAAK5G,aACRD,YAAajE,CACjB,CAAC,CAAC,EAEFvC,IAAI8Q,EACJ,IACIA,EAAmBzQ,MAAMgN,KAAK0D,WAAWlP,CAAW,CAIxD,CAHE,MAAO1B,GAEL,OADAkN,KAAAA,KAAK8B,wBAAwBhP,EAAMM,OAAO,CAE9C,CAGA0P,EAAaU,SAAW,CAAA,EACxBV,EAAazD,MAAMsE,OAAS,UAEvBF,EAAiBG,cAKaxR,KAAAA,IAA9BqR,EAAiBI,WAClB7D,KAAK5G,aAAayK,SAAWJ,EAAiBI,UAIlD7D,KAAKJ,aAAe5M,MAAMsH,YAAY0F,KAAKlK,MAAM,EAEjDqM,2BAA2BnC,KAAKJ,YAAY,EAE5CI,KAAK5G,aAAe,GACpBpG,MAAMgN,KAAKqC,oBAAoB,YAAY,EAC3CZ,yBAAyB,CAAA,CAAK,EAC9BqC,sBAAsB,CAAA,CAAK,EAnH3B,MANIb,EAAuB5D,MAAMkE,YAAc,MAC3CN,EAAuB9F,MAAM,EAC7B8F,EAAuBnE,iBAAiB,QAAS,WAC7CkB,KAAKX,MAAMkE,YAAc,EAC7B,CAAC,CARL,MANIR,EAAiB1D,MAAMkE,YAAc,MACrCR,EAAiB5F,MAAM,EACvB4F,EAAiBjE,iBAAiB,QAAS,WACvCkB,KAAKX,MAAMkE,YAAc,EAC7B,CAAC,CAgIT,CAAC,CAET,CAMAlB,0BAA0BtC,EAAMgE,EAAsB,CAAA,GAClD,IAAMC,EAAkBpH,SAASC,cAAc,sBAAsB,EAAID,SAASC,cAAc,sBAAsB,EAAID,SAASqH,cAAc,KAAK,EACtJD,EAAgBE,UAAY,sBAC5BF,EAAgBG,UAAYpH,WAAW,EAAE,EACzCiH,EAAgBI,gBAAgB,OAAO,EAEvCzR,IAAI0R,EAAe,GACfC,EAEAC,EAAoB,GAExB,OAAQxE,GACJ,IAAK,eACDsE,EAAe,eACfrE,KAAKwE,UAAYH,EACjBE,EAAoB,CAChBrL,aAAc8G,KAAK9G,aACnBuL,cAAe7H,SAAS3C,SAASyK,UAAY,GAC7CxE,kBAAmBC,iBAAiBC,aAAa,mBAAmB,EACpEC,iBAAkBF,iBAAiBC,aAAa,kBAAkB,EAClE,GAAGJ,KAAKH,YACZ,EACA8E,wBAAwB,GAAKlD,yBAAyB,CAAA,CAAK,EAC3D,MACJ,IAAK,OACD,GAAImD,yBAAyB,EACzB,OAEJP,EAAe,OACfE,EAAoB,CAAC,GAAGvE,KAAKH,YAAY,EACzC,MACJ,IAAK,cACDwE,EAAe,cACfE,EAAoB,CAAC,GAAGvE,KAAKH,YAAY,EACzC,MACJ,IAAK,aACDwE,EAAe,aACfrE,KAAKwE,UAAYH,EACjBE,EAAoB,CAAC,GAAGvE,KAAKH,YAAY,EACzC,MACJ,IAAK,YACDwE,EAAe,YACf,IAAMQ,EAAgBhQ,aAAaC,QAAQ,qBAAqB,EAChEyP,EAAoB,CAChBO,eAAgBD,EAAgB,mBAAqBA,EAAgB,IAAM,GAC3EzI,OAAQ+D,iBAAiBC,aAAa,YAAY,EAClD2E,QAAS5E,iBAAiBC,aAAa,SAAS,EAChD4E,SAAU7E,iBAAiBC,aAAa,UAAU,EAClD6E,gBAAiB9E,iBAAiBC,aAAa,iBAAiB,EAChE8E,sBAAuB/E,iBAAiBC,aAAa,uBAAuB,EAC5E1D,SAAU,QACVtI,MAAO,GACP,GAAG4L,KAAKH,YAAY,EACxB,MACJ,IAAK,iBACDwE,EAAe,iBACfrE,KAAKwE,UAAYH,EAEjBrE,KAAKL,uBAAyBwF,MAAMC,QAAQpF,KAAKJ,YAAY,EAAII,KAAKJ,aAAanH,OAAS,EAE5FuH,KAAKN,0BAA4ByF,MAAMC,QAAQpF,KAAKJ,YAAY,EAC1DI,KAAKJ,aAAarF,OAAOpD,IACvB,IAEI,OADaA,EAAK/B,SAAW4D,KAAKC,MAAM9B,EAAK/B,QAAQ,EAAI,IAC7CoB,UAAYwD,OAAOC,SAASC,IAChB,CAA1B,MAAOmL,GAAK,MAAO,CAAA,CAAO,CAChC,CAAC,EAAE5M,OACD,EAEN8L,EAAoB,CAChBvM,WAAY,MACZsN,cAAe,GACfC,cAAexJ,uBAAuBiE,KAAKN,0BAA2BM,KAAKL,sBAAsB,EACjG,GAAGK,KAAKH,YACZ,CAIR,CAOA,OANAmE,EAAgBG,UAAYnE,KAAKwF,aAAanB,EAAcE,CAAiB,EAC7E3H,SAAS1J,KAAKuS,YAAYzB,CAAe,EAGzC0B,wBAAwB,EAEhB3F,GACJ,IAAK,eAED,IAAM4F,EAAY3L,OAAO4L,aAAa,EAChCC,EAAkB,CAAC,CAAChR,aAAaC,QAAQ,oBAAoB,EAC7DV,EAAQS,aAAaC,QAAQ,eAAe,EAC9C+Q,GAAmBzR,GAAS,CAACA,EAAMyG,SAAS,UAAU,GACtD+B,SAASC,cAAc,4BAA4B,EAAEG,UAAU8I,IAAI,QAAQ,EAGxD,UAAnBH,EAAU5F,OAGVgG,wBADqBC,uBAAuBL,CAAS,EAChBM,QAAQ,EAC7CjG,KAAKkG,wBAAwB,GAGjClG,KAAK6C,qBAAqB,EAC1B,MACJ,IAAK,OACD7P,MAAMgN,KAAKmG,aAAa,EACxBvJ,SAASC,cAAc,2BAA2B,EAAEiC,iBAAiB,QAAS,IACpEsH,EAAuBf,EAAEgB,cAAcrJ,UACzCoJ,GAAwB,CAACA,EAAqBjD,SAAS,QAAQ,GAC/DnD,KAAKqC,oBAAoB,YAAY,CAE7C,CAAC,EACDyB,sBAAsB,CAAA,CAAK,EAC3B,MACJ,IAAK,cACDlH,SAASC,cAAc,6BAA6B,EAAEiC,iBAAiB,QAAS,IAC5EwH,kBAAkBtG,KAAK5G,aAAc,cAAc,CACvD,CAAC,EACD,MACJ,IAAK,aACDsM,wBAAwB,EACxB/S,IAAI4T,EAAuB,EACtBvG,KAAKJ,cAAcnH,SACpBuH,KAAKJ,aAAe5M,MAAMsH,YAAY0F,KAAKlK,MAAM,GAErD,IAAMmB,EAAQ+I,KAAKJ,aAEf4G,GADJlC,EAAmBtR,MAAMyG,oBAAoBuG,KAAKlK,OAAQmB,EAAO+I,KAAKtG,mBAAmB,EAC9D,IAC3B,GAAmB,EAAfzC,EAAMwB,OAAY,CAClB,IAAMgO,EAAazM,OAAOC,SAASC,KACnC,IAAMwM,EAAczP,EAAM0P,KAAK,CAACC,EAAGC,KACzBC,EAAU9N,KAAKC,MAAM2N,EAAExR,QAAQ,EAAEoB,UAAYiQ,EAAa,EAAI,EAEpE,OADgBzN,KAAKC,MAAM4N,EAAEzR,QAAQ,EAAEoB,UAAYiQ,EAAa,EAAI,GACnDK,CACrB,CAAC,EAEDlK,SAASC,cAAc,2CAA2C,EAAEsH,UAAY,GAEhF,IAAKxR,IAAIoU,EAAI,EAAGA,EAAIL,EAAYjO,OAAQsO,CAAC,GAAI,CACzC,IAAMC,EAASN,EAAYK,GAGrBzR,EAAS0R,EAAO1R,OAChBN,EAAYgS,EAAOhS,UACnBiS,EAAiBD,EAAO5R,SAC9BzC,IAAIuU,EAAW,KACf,GAAID,EACA,KACIC,EAAWlO,KAAKC,MAAMgO,CAAc,GAC3BE,QAAgC,SAAtBH,EAAOtP,WAC1BwP,EAAS5R,OAAS0R,EAAO1R,MAG7B,CAFE,MAAOxC,GACLoU,EAAW,IACf,CAEJ,IAsBUE,EAEAC,EAxBJC,EAAiBJ,EAAWA,EAAS1Q,QAAU,GAC/C+Q,EAAeL,EAAWA,EAASjB,SAAW,GAGpDtT,IAAI6U,EAAyB,GACzBC,EAAuB,4BACvBP,GAAkC9U,KAAAA,IAAtB8U,EAASrD,WAGjB4D,EAFAP,EAASrD,UACT2D,EAAyBxH,KAAKH,aAAae,eACpB,uBAEvB4G,EAAyBxH,KAAKH,aAAagB,gBACpB,sEAI5ByG,IAAmBtN,OAAOC,SAASC,MAClCqM,CAAoB,GAGnBxC,GAAuBuD,IAAmBtN,OAAOC,SAASC,OAIrDmN,EAAaK,cAFbN,EAAkBO,mBAAmBrD,EAAkBhP,CAAM,CAEnB,EAC1CsS,EAA8B,CAChC5S,UAAWA,GAAa,GACxB4G,uBAAwBwL,EAAgBxL,uBACxCC,eAAgBuL,EAAgBvL,eAChC2L,uBAAwBA,EACxBC,qBAAsBA,EACtBI,gBAAiB9K,WAAWqK,EAAgBU,eAAe,EAC3DC,YAAaT,EACbxG,cAAed,KAAKH,aAAaiB,cACjCkH,qBAAsBnK,gBAAgByJ,CAAc,EACpDlQ,eAAgBgQ,EAAgBa,gBAChChC,SAAUjG,KAAKkI,iBAAiBX,CAAY,EAC5CjS,OAAQA,EACR6S,eAAgBd,EAAWc,eAC3BC,YAAaf,EAAWe,YACxBC,mBAAoBhB,EAAWgB,mBAC/BC,cAAejB,EAAWiB,cAC1BC,YAAa,GACbC,kBAAyC,SAAtBxB,EAAOtP,WAAwB,GAAK,qCACvD+Q,gBAAuC,SAAtBzB,EAAOtP,WAAwB,GAAKsI,KAAKwF,aAAa,WAAW,CACtF,EAE+BkD,oCAAoCtB,EAAgB9R,MAAM,IAErFsS,EAA4BW,YAAc,UAE9C3L,SAASC,cAAc,2CAA2C,EAAEsH,WAAanE,KAAKwF,aAAa,cAAeoC,CAA2B,EAExI5H,KAAK2I,0BAA0BzB,CAAQ,GACxCV,EAAqBhI,KAAK0I,CAAQ,EAG9C,CACAlH,KAAKN,0BAA4B6G,EACjCvG,KAAKL,uBAAyB1I,EAAMwB,OACpCmQ,yBAAyBpC,EAAsBxG,IAAI,EACnDpD,SAASC,cAAc,kCAAkC,EAAEsH,WAAapH,WAAW,IAAMhB,uBAAuBiE,KAAKN,0BAA2BM,KAAKL,sBAAsB,CAAC,CAChL,CAEqB,IAAjB1I,EAAMwB,SACNmE,SAASC,cAAc,2CAA2C,EAAEsH,UAAYpH,WAAW,mFAAmF,GAIlLiD,KAAK6I,gBAAgB,EACrB/E,sBAAsB,CAAA,CAAK,EAC3B,MACR,IAAK,YAEGpF,gBAAgBsB,IAAI,EACpBb,4BAA4B,EAEtB2J,EAAO9V,MAAM6G,eAAemG,KAAKlK,MAAM,EACvCiT,EAAmB/V,MAAMwF,kBAAkB,EAE3CwQ,EAAUnU,aAAaC,QAAQ,qBAAqB,GAAKiU,EAG/DxE,EAAkBO,gBAFDkE,qBAA6BA,KAAa,KAEN,GAElDF,IACCvE,EAAkB7H,SAAWoM,EAAK/T,MAAQ,QAC1CwP,EAAkBnQ,MAAQ0U,EAAK1U,OAAS,GACrC0U,GAAM1M,QAAQ6M,KAAG1E,EAAkBnI,OAAS0M,GAAM1M,QAAQ6M,GAGjEjF,EAAgBG,UAAYnE,KAAKwF,aAAa,YAAajB,CAAiB,EAC5E3H,SAAS1J,KAAKuS,YAAYzB,CAAe,EACzCtF,gBAAgBsB,IAAI,EACpBb,4BAA4B,EAE5B,MACR,IAAK,iBAGG,IAAM3K,EAAcxB,MAAM2U,mBAD1BrD,EAAmBtR,MAAMyG,oBAAoBuG,KAAKlK,OAAQkK,KAAKJ,aAAcI,KAAKtG,mBAAmB,EACtCsG,KAAKtG,mBAAmB,EAGjFwP,EAAoBtM,SAASC,cAAc,kCAAkC,EAC/EqM,IACAA,EAAkBpM,UAAYC,WAAWvI,EAAYwD,UAAU,GAGnEuM,EAAkBvM,WAAaxD,GAAawD,WAC5CuM,EAAkBe,cAAgB9Q,GAAa8Q,cAE/CtB,EAAgBG,UAAYnE,KAAKwF,aAAa,iBAAkBjB,CAAiB,EACjF3H,SAAS1J,KAAKuS,YAAYzB,CAAe,EAGzCrR,IAAIsT,EAAW,KACLkD,EAAkBnJ,KAAKJ,aAAajG,KAAK,GAAayP,OAAOtN,EAAQxG,MAAM,IAAM8T,OAAO5U,EAAYc,MAAM,CAAC,EACjH3C,IAAIwC,EAAO,KACX,GAAIgU,GAAmBA,EAAgB/T,SACnC,IACID,EAAO6D,KAAKC,MAAMkQ,EAAgB/T,QAAQ,EAC1C6Q,EAAW9Q,EAAK8Q,UAAY,IACY,CAA1C,MAAOZ,GAAKY,EAAW,KAAM9Q,EAAO,IAAM,CAGhDuQ,wBAAwB,EACpBvQ,GAAQ8Q,IAER2C,yBAAyB,CAACzT,GAAO6K,IAAI,EACE,YAAnC,OAAO+F,0BACPA,wBAAwBE,CAAQ,EAI5C,IAAMoD,EAA0BzM,SAASC,cAAc,gDAAgD,EACnGyM,EAAkB,GAChBC,EAAe1U,aAAaC,QAAQ,iBAAiB,EAE3D,GAAwC,EAAnCN,EAAY8Q,cAAc7M,OAAa,CACxC+Q,mCAAmChV,EAAYc,MAAM,EACrD+T,EAAwBlF,UAAYpH,WAAW,EAAE,EACjD,IAAK,IAAM9H,KAAWT,EAAY8Q,cAAe,CAE7C,IADAmE,EAAeC,OAAOH,CAAY,IAAMG,OAAOzU,EAAQ0U,aAAa,EAC9DtC,EAAaK,cAAc,CAC7B9L,uBAAwB3G,EAAQ2U,uBAChC/N,eAAgB5G,EAAQ4U,iBAC5B,CAAC,EACKC,EAAc,CAChBD,kBAAmB5U,EAAQ4U,kBAC3B/R,YAAa7C,EAAQ6C,YACrBC,YAAa9C,EAAQ8C,YACrBgS,YAAa9U,EAAQ8U,YACrB/R,WAAYuM,EAAkBvM,WAC9BmQ,eAAgBd,EAAWc,eAC3BC,YAAaf,EAAWe,YACxBC,mBAAoBhB,EAAWgB,mBAC/BC,cAAejB,EAAWiB,cAC1B0B,uBAAwBP,EAAe,QAAU,OACrD,EAC6CrX,KAAAA,IAAzCkX,EAAgBrU,EAAQ8C,eACxBuR,EAAgBrU,EAAQ8C,aAAe,IAGvCuR,EAAgBrU,EAAQ8C,aAAayG,KAAKsL,CAAW,CAE7D,CACAnX,IAAIsX,EAAkB,GAEtB,IAAK,IAAMC,KAAOZ,EAAiB,CAC/B3W,IAGWwX,EAHPC,EAAqBd,EAAgBY,GACzCvX,IAAI0X,EAAyB,GAE7B,IAAWF,KADXC,EAAmBzD,KAAK,CAACC,EAAGC,IAAMD,EAAEmD,YAAYO,cAAczD,EAAEkD,WAAW,CAAC,EACpDK,EAAoB,CACxCzX,IAAI4X,EAAkCH,EAAmBD,GACzDE,GAA0BrK,KAAKwF,aAAa,0BAA2B+E,CAA+B,CAC1G,CACAN,GAAmBjK,KAAKwF,aAAa,6BACjC,CACIgF,mBAAoBN,EACpBO,mBAAoBJ,EACpB5B,gBAAkD,SAAjCnE,GAAkB5M,WAAwB,GAAKsI,KAAKwF,aAAa,eAAe,CACrG,CACJ,CACJ,CACA6D,EAAwBlF,UAAY8F,CACxC,MACIZ,EAAwBlF,UAAYpH,WAAW,aAAa,EAI1D2N,EAAW9N,SAASC,cAAc,yCAAyC,EAE7E,SAAS8N,IACgB,GAEjB3K,KAAKgD,MAAMvK,OACXuH,KAAKhD,UAAU8I,IAAI,MAAM,EAEzB9F,KAAKhD,UAAUC,OAAO,MAAM,CAEpC,CATAyN,IAUAA,EAAS5L,iBAAiB,QAAS6L,CAAoB,EACvDD,EAAS5L,iBAAiB,SAAU6L,CAAoB,GAI5D7G,sBAAsB,EAGtB9E,WAAW,KACP,IAAM4L,EAAmBhO,SAASC,cAAc,8BAA8B,EAC9E+N,EAAiBC,SAAS,CACtBC,IAAKF,EAAiBG,aACtBC,SAAU,QACd,CAAC,CACL,EAAG,CAAC,EAEJ,IAAMC,EAAarO,SAASC,cAAc,0CAA0C,EACpF,GAAIoO,EAAY,CACZjL,KAAKe,aAAad,KAAK,EACvBtN,IAAIuY,EAAclL,KAClBiL,EAAWnM,iBAAiB,QAAS9M,MAAOqT,IACxCA,EAAE8F,eAAe,EAEjB,IACMC,EADuBH,EAAW1L,QAAQ,mCAAmC,EAChD1C,cAAc,yCAAyC,EAEpFzC,EAAcgR,EAAMpI,MAAMzG,KAAK,EACrC,GAAKnC,EAAL,CAIAgR,EAAM5H,SAAW,CAAA,EACjByH,EAAWzH,SAAW,CAAA,EAEtB7Q,IAAI0Y,EAAqB,KAEzB,IACIA,EAAqBrY,MAAMmH,eAAe6F,KAAKlK,OAAQkK,KAAKtG,oBAAqBU,CAAW,EAC5FgR,EAAMpI,MAAQ,GACdhQ,MAAMgN,KAAKqC,oBAAoB,gBAAgB,EAC/CyB,sBAAsB,CAAA,CAAK,CAG/B,CAFE,MAAOlL,GACL0S,MAAM,gCAAkC1S,EAAIxF,OAAO,CACvD,CAEI8X,EAAYnK,aAAawK,SAAS,GAA4B,OAAvBF,GAA+BA,EAAmB5Y,eAAe,WAAW,IAC7GuB,EAAYa,aAAaC,QAAQ,oBAAoB,GACrD0W,EAAwBxY,MAAMkY,EAAYnK,aAAa0K,0BAA0BP,EAAYpV,OAAQ9B,EAAWqX,EAAmB3V,SAAS,GACvH6C,UACvB2S,EAAYnK,aAAa2K,UAAU,uDAAuD,EACpFC,EAAY3S,KAAKK,UAAUmS,CAAqB,EACtDI,QAAQC,IAAIF,CAAS,IAI7BP,EAAM5H,SAAW,CAAA,EACjByH,EAAWzH,SAAW,CAAA,CA7BE,CA8B5B,CAAC,CACL,CAKR,CAEMsI,EAA4BlP,SAASC,cAAc,oCAAoC,EAC7F,IAAMqO,EAAclL,KACf8L,GACDA,EAA0BhN,iBAAiB,QAAS,SAASuG,EAAG0G,EAAOb,GACnEa,EAAK1J,oBAAoB,YAAY,CACzC,CAAC,EAGC2J,EAAsBpP,SAASC,cAAc,6CAA6C,EA2BhG,OA1BKmP,GACDhM,KAAKe,aAAakL,oBAAoBD,CAAmB,EAG7DpP,SAASC,cAAc,gCAAgC,GAAGiC,iBAAiB,QAAS,IAChFkB,KAAKf,KAAK,CACd,CAAC,EAEDrC,SAASC,cAAc,qBAAqB,GAAGiC,iBAAiB,QAAS,KACrEkB,KAAKqC,oBAAoB,WAAW,CACxC,CAAC,EAEDzF,SAASC,cAAc,+CAA+C,GAAGiC,iBAAiB,QAAS,KAC/FoN,kBAAkB,CACtB,CAAC,EAEDtP,SAASC,cAAc,sBAAsB,GAAGiC,iBAAiB,QAAS,KACtEkB,KAAKqC,oBAAoBrC,KAAKwE,SAAS,CAC3C,CAAC,EAQMR,CACX,CAEA6E,kBACIjM,SAASuP,iBAAiB,aAAa,EAAEC,QAAQxS,IAC7CA,EAAKkF,iBAAiB,QAAS9M,UAC3BW,IAAIsT,EAAW,KACf,IACIA,EAAWjN,KAAKC,MAAMW,EAAKyS,aAAa,gBAAgB,CAAC,CAG7D,CAFE,MAAOvZ,GACLmT,EAAW,IACf,CACIA,GACAF,wBAAwBE,CAAQ,EAEpCjG,KAAKtG,oBAAsBE,EAAKyS,aAAa,cAAc,EAC3DrZ,MAAMgN,KAAKsM,YAAY,CAC3B,CAAC,CACL,CAAC,CACL,CAQAA,oBACItZ,MAAMgN,KAAKqC,oBAAoB,gBAAgB,EAC/C,IAAMkK,EAAoBvM,KAAKwM,qBAAqBxM,KAAKtG,mBAAmB,EAExE6S,IACA7G,wBAAwB,EACxBkD,yBAAyB,CAAC2D,GAAoBvM,IAAI,EAClDA,KAAKkG,wBAAwB,GAGjCpC,sBAAsB,CAAA,CAAK,CAC/B,CAWA0B,aAAanB,EAAcoI,EAAY,IACnC9Z,IAAI+Z,EAAWC,uBAAuBC,gBAAgBvI,CAAY,EAElE,IAAK,GAAM,CAAC/R,EAAK0Q,KAAUP,OAAOG,QAAQ6J,CAAS,EAAG,CAC5CI,OAAmBva,MACzBK,IAAIma,EAOAA,EAFA9M,KAAK+M,yBAAyBL,EAAUG,CAAW,EAErC7M,KAAKiB,WAAWmI,OAAOpG,CAAK,CAAC,EAG7BjG,WAAWqM,OAAOpG,CAAK,EAAG,CAAC0J,SAAUrI,EAAc2I,UAAW,CAAA,CAAI,CAAC,EAGrFN,EAAWA,EAASO,WAAWJ,EAAaC,CAAW,CAC3D,CAEA,OAAO/P,WAAW2P,EAAU,CAACA,SAAUrI,CAAY,CAAC,CACxD,CAQA0I,yBAAyBL,EAAUG,GAEzBK,EAAqBL,EAAY9R,QAAQ,QAAS,MAAM,EAY9D,OAPyB,IAAIoS,oCACID,cAC7B,GACJ,EAIwBE,KAAKV,CAAQ,CACzC,CAEAzL,WAAa,GACFoM,EACFtS,QAAQ,KAAM,OAAO,EACrBA,QAAQ,KAAM,MAAM,EACpBA,QAAQ,KAAM,MAAM,EACpBA,QAAQ,KAAM,QAAQ,EACtBA,QAAQ,KAAM,QAAQ,EAG/BoL,qBACI,GAAI,CAACtR,aAAaC,QAAQ,oBAAoB,EAC1C,MAAO,GAGX,IAAMJ,EAAesL,KAAKlK,OAAOpB,aAC3BV,EAAYa,aAAaC,QAAQ,oBAAoB,EAErDwY,EAAezY,aAAaC,QAAQ,qBAAqB,EAE/DnC,IAAI4a,EAQGA,EANa,IAAjBD,GAAuBA,EAMNA,GALFta,MAAMgE,gBAAgBtC,EAAcV,EAAWgM,KAAKlK,OAAO3D,UAAW6N,KAAKlK,OAAOlB,SAAS,GAC7E2F,OAAOpD,GACxBA,EAAK/B,QACf,EAC0BqD,OAGzB+U,EAAmB5Q,SAASM,eAAe,gCAAgC,EAC5EsQ,IACDA,EAAiB1Q,UAAYC,WAAWwQ,CAAU,EAClDC,EAAiBxQ,UAAUC,OAAO,QAAQ,EAElD,CAYAyG,iBAAiBlP,GACRK,aAAaC,QAAQ,oBAAoB,IAC1C9B,MAAMwJ,aAAahI,CAAW,EAAEwL,KAAK8B,uBAAuB,EACvDtN,EAAYgJ,cACbxK,MAAMuK,UAAU/I,CAAW,EAAEwL,KAAK8B,uBAAuB,GAIjE,IAAM9N,EAAYa,aAAaC,QAAQ,oBAAoB,EAE3D,OAAOd,EAIMuF,iBAAiBvF,EAAWQ,CAAW,EAFzC,CAACoP,YAAa,CAAA,CAAI,CAGjC,CAKA3E,OACIyG,wBAAwB,EACxB1F,KAAKqC,oBAAoB,MAAM,CACnC,CAEAoL,gCAAgC3R,GAC5B,IAAM4R,EAAa5R,EAAQ6R,UAAU,EAC/BC,EAAUhR,SAASqH,cAAc,MAAM,EAM7C,OALA2J,EAAQ1J,UAAY,qDAEpBpI,EAAQ+R,sBAAsB,cAAeD,CAAO,EACpDA,EAAQnI,YAAYiI,CAAU,EAEvBE,CACX,CAOApB,qBAAqBsB,GACjB,IAAM3E,EAAkBnJ,KAAKJ,aAAajG,KAAK,GAAamC,EAAQxG,OAAOkG,SAAS,IAAMsS,EAAetS,SAAS,CAAC,EACnH,GAAI2N,GAAgD/W,KAAAA,IAA7B+W,EAAgB/T,SAAwB,CAC3DzC,IAAIob,EAAsB,KAC1B,IACIA,EAAsB/U,KAAKC,MAAMkQ,EAAgB/T,QAAQ,CAG7D,CAFE,MAAOtC,GACLib,EAAsB,IAC1B,CACA,GAA4B,OAAxBA,GAA+D,UAA/B,OAAOA,EACvC,OAAOA,CAEf,CACA,OAAO,IACX,CAEAzL,8BAEmB1F,SAASuP,iBAAiB,4BAA4B,EAC9DC,QAAQhB,IACPA,EAAMpI,OACNoI,EAAMpO,UAAU8I,IAAI,WAAW,EAGnCsF,EAAMtM,iBAAiB,QAAS,KACxBsM,EAAMpI,MACNoI,EAAMpO,UAAU8I,IAAI,WAAW,EAE/BsF,EAAMpO,UAAUC,OAAO,WAAW,CAE1C,CAAC,EAEDmO,EAAMtM,iBAAiB,OAAQ,KACtBsM,EAAMpI,OACPoI,EAAMpO,UAAUC,OAAO,WAAW,CAE1C,CAAC,CACL,CAAC,EAnBD,IAsBM+Q,EAAsBpR,SAASC,cAAc,iCAAiC,EACpF,GAAKmR,EAAsB,CACvB,IAAMC,EAAUjO,KAChBgO,EAAoBlP,iBAAiB,QAAS,WAC1CkB,KAAKT,QAAQ,4BAA4B,EAAEvC,UAAU4B,OAAO,QAAQ,EAEpEqP,EAAQ/H,wBAAwB,EAChClH,WAAW,KACP,IAAM4L,EAAmBhO,SAASC,cAAc,8BAA8B,EAC9E+N,EAAiBC,SAAS,CACtBC,IAAKF,EAAiBG,aACtBC,SAAU,QACd,CAAC,CACL,EAAG,CAAC,CACR,CAAC,CACL,CAEAhR,OAAO8E,iBAAiB,SAAUkB,KAAKkO,aAAaC,KAAKnO,IAAI,CAAC,EAC9DhG,OAAO8E,iBAAiB,SAAUkB,KAAKoO,aAAaD,KAAKnO,IAAI,CAAC,CAClE,CAEA8B,wBAAwBuM,EAAatO,EAAO,SACxC,IAAMuO,EAAY1R,SAASM,eAAe,0CAA0C,EAC9EqR,EAAa3R,SAASM,eAAe,mCAAmC,EACxEsR,EAAc5R,SAASC,cAAc,sCAAsC,EAEtD,UAAvB,OAAOwR,GAA2C,OAAfE,GAAuC,OAAhBC,IAC1DD,EAAWzR,UAAYC,WAAWsR,CAAW,EAC7CG,EAAYxR,UAAUC,OAAO,QAAQ,EACrCsR,EAAWvR,UAAUC,OAAO,qCAAsC,mCAAmC,EACxF,WAAT8C,GACAuO,EAAUxR,UAAYC,WAAW,EAAE,EACnCyR,EAAYxR,UAAU8I,IAAI,oCAAoC,EAC9DyI,EAAWlP,MAAMoP,MAAQ,YAEzBH,EAAUxR,UAAYC,WAAW,oBAAoB,EACrDyR,EAAYxR,UAAU8I,IAAI,mCAAmC,EAC7DyI,EAAWlP,MAAMoP,MAAQ,OAGrC,CAEAvI,0BACI,IAAMP,EAAY/I,SAASC,cAAc,qCAAqC,EACxE6R,EAAS9R,SAASC,cAAc,sBAAsB,EACtD8R,EAAoB/R,SAASC,cAAc,+DAA+D,EAC1G+R,EAAsBhS,SAASC,cAAc,gDAAgD,EACnG,IAAW8R,GAAqBC,IAAyBjJ,EAAzD,CAKA,IAAMkJ,EAAU7U,OAAO6U,QACjBC,EAAiB9U,OAAO+U,YAExBC,EAAuBrJ,EAAUsJ,sBAAsB,EAAEnE,IAAM+D,EAE/DK,EAAeR,EAAOS,aAE5Bxc,IAAImY,EAGAkE,EAAuBH,EAAU,EAEjC/D,EAAM,IACkCgE,EAAjCE,EAAuBH,GAMQC,EAAiBI,GADvDpE,EAAMkE,EAAuBH,MAGzB/D,EAAMgE,EAAiBI,EAAe,IAI9CR,EAAOrP,MAAMyL,IAASA,EAAH,KACnB4D,EAAOrP,MAAM+P,OAAS,MA5BtB,CA6BJ,CAEAlB,eACIhP,aAAac,KAAKqP,aAAa,EAC/BrP,KAAKqP,cAAgBrQ,WAAW,KAC5BgB,KAAKkG,wBAAwB,CACjC,EAAG,EAAE,CACT,CAEAkI,eACIlP,aAAac,KAAKsP,aAAa,EAC/BtP,KAAKsP,cAAgBtQ,WAAW,KAC5BgB,KAAKkG,wBAAwB,CACjC,EAAG,GAAG,CACV,CAOAyC,0BAA0BzB,GACtB,MAAO,CAAA,CACX,CAEAgB,iBAAiBjC,GACbsJ,EAAMpK,MAAMC,QAAQa,CAAQ,EAAIjN,KAAKK,UAAU4M,CAAQ,EAAImD,OAAOnD,CAAQ,EAE9E,MAAI,kBAAkBmH,KAAKmC,CAAG,EACnBA,EAEJ,EACX,CACA,CAEA,IAAIC,wBAA0B,KAC9B,IAAMC,cAAgB,CAAA,EAChBC,mBAAqB,IAQ3B,SAASC,cACL,IAAIC,qBACJ,IAAIpQ,uBAAuB,GAAI,MAAM,CACzC,CA8CA,SAAS0M,oBACL,IAAI1M,uBAAuB,KAAM,cAAc,CACnD,CAOA,SAASqQ,sBAAsBC,GAC3B,GAAKA,EAAL,CACAnd,IAAIyM,EAAK0Q,EAAKC,WAAaC,KAAKC,aAAeH,EAAOA,EAAKI,cAC3D,KAAO9Q,GAAI,CACP,GAAIA,EAAGpC,WAAaoC,EAAGpC,UAAUmG,SAAS,qBAAqB,EAC3D,MAAO,CAAA,EAEX/D,EAAKA,EAAG8Q,aACZ,CAPuB,CAQvB,MAAO,CAAA,CACX,CAOA,SAAS5J,kBAAkBlN,EAAc2G,GACjC3G,GACA,IAAIoG,uBAAuBpG,EAAc2G,CAAI,CAErD,CAOA,SAASoQ,gBAAgB/c,GAChBqc,eACD7D,QAAQC,IAAIzY,CAAO,CAE3B,CAEA,SAAS0Q,wBACL,IAAMsM,EAAWxT,SAASyT,uBAAuB,oDAAoD,EACrG,GAAsB,EAAlBD,EAAS3X,OACT,IAAK9F,IAAIoU,EAAI,EAAGA,EAAIqJ,EAAS3X,OAASsO,CAAC,GACnCqJ,EAASrJ,GAAG1H,MAAMC,QAAU,OAGpC,IAAMgR,EAAyB,CAAC,2CAA4C,iDAC5E,IAAK3d,IAAIoU,EAAI,EAAGA,EAAIuJ,EAAuB7X,OAASsO,CAAC,GAAI,CACrD,IAAMwJ,EAAa3T,SAASyT,uBAAuBC,EAAuBvJ,EAAE,EAC5E,GAAwB,EAApBwJ,EAAW9X,OACX,IAAK9F,IAAIoU,EAAI,EAAGA,EAAIwJ,EAAW9X,OAASsO,CAAC,GACrCwJ,EAAWxJ,GAAG1H,MAAMC,QAAU,OAG1C,CACJ,CAEA,SAASqI,mBAAmB6I,EAAclb,GACtC,IAAMuC,EAAW2Y,EAAa3Y,SAAS0C,OAAOtF,GACnCA,EAAQK,QAAQkG,SAAS,IAAMlG,GAAQkG,SAAS,CAC1D,EACD,IAAMrD,EAAQqY,EAAarY,MAEvBsY,EAAgC,EAAlB5Y,EAASY,OAAaZ,EAAS,GAAK,KAElDsE,EAAS,KAKExB,GAJX8V,GAAetY,GAAwB,EAAfA,EAAMM,SAC9B0D,EAAShE,EAAMwB,KAAKqE,GAAKoL,OAAOpL,EAAE7J,OAAO,IAAMiV,OAAOqH,EAAYvc,MAAM,CAAC,GAGvD,IAClBuc,KACMC,EAAKlW,WAAWiW,EAAY1Y,WAAW,GACnC2C,KACVC,EAAO+V,EAAG/V,MAGdhI,IAAIge,EAAYzU,aAAaC,CAAM,EAC/ByU,EAAatU,cAAcH,CAAM,EAErC,MAAO,CACH7G,OAAQA,EACRsG,uBAAwB+U,EACxB9U,eAAgB+U,EAChB9I,gBAAiB2I,EAAcA,EAAY3Y,YAAc,kBACzDmQ,gBAAiBtN,EACjB3C,WAA8B,EAAlBH,EAASY,OAAaZ,EAAS,GAAGG,WAAa,WAC3DsN,cAAezN,EACV8O,KAAK,CAACC,EAAGC,IACC,IAAI/L,KAAK8L,EAAE7O,WAAW,EAAI,IAAI+C,KAAK+L,EAAE9O,WAAW,CAC1D,EACAb,IAAIjC,IACD,GAAM,CAACyF,KAAAA,EAAMC,KAAAA,CAAI,EAAIH,WAAWvF,EAAQ8C,WAAW,EACnDpF,IAAIwJ,EAAS,KAIb,MAAO,CACHyN,uBAAwB1N,aAHxBC,EADAhE,GAAwB,EAAfA,EAAMM,OACNN,EAAMwB,KAAKqE,GAAKoL,OAAOpL,EAAE7J,OAAO,IAAMiV,OAAOnU,EAAQf,MAAM,CAAC,EAGhCiI,CAAM,EAC3C0N,kBAAmBvN,cAAcH,CAAM,EACvCrE,YAAa7C,EAAQ6C,YACrBC,YAAa2C,EACbqP,YAAapP,EACbgP,cAAe1U,EAAQf,QAAU,cACrC,CACJ,CAAC,CACT,CACJ,CAEA,SAASwT,cAAcmJ,GACnBle,IAAIyV,EACAD,EACJxV,IAAI0V,EACAwI,EAAchV,gBAAkD,aAAhCgV,EAAchV,eACxCgV,EAAchV,eAAeU,KAAK,EAAEuU,OAAO,CAAC,EAAEC,YAAY,EAC1D,KACVpe,IAAI2V,EAAgB,sCAepB,OAd6C,OAAzCuI,EAAcjV,wBAA0D,OAAvByM,IACjDD,EAAc,uFACdD,EAAiB,wCAEwB,OAAzC0I,EAAcjV,wBAA0D,OAAvByM,IACjDD,EAAc,0jPACdD,EAAiB,uCACjBG,GAAiB,uCAEwB,OAAzCuI,EAAcjV,yBACdwM,2BAAwCyI,EAAcjV,4BACtDuM,EAAiB,uCACjBG,EAAgB,sCAEb,CACHF,YAAaA,EACbD,eAAgBA,EAChBE,mBAAoBA,EACpBC,cAAeA,CACnB,CACJ,CAOA,SAAS0I,iBAAiBpR,GACtBjN,IAEMse,EAAkB,GAExB,IAAKte,IAAIoU,EAAI,EAAGA,EAAInH,EAAanH,OAAQsO,CAAC,GAAI,CAC1C,IAAMmK,EAAqBtR,EAAamH,GAClCoK,EAAWtc,aAAaC,QAAQ,iBAAiB,EAEnDoc,EAAmB5b,QACnB4b,EAAmB9Z,gBACnB8Z,EAAmB1Z,oBAAoBgE,SAAS,IAAM2V,EAAS3V,SAAS,GAE/D4V,uBAAuBF,EAAmB5b,OAAQ4b,EAAmB9Z,cAAc,GAExF6Z,EAAgBzS,KAAK0S,EAAmB5b,OAAOkG,SAAS,CAAC,CAGrE,CAEA,OAAkC,IAA3ByV,EAAgBxY,QAAuBwY,CAClD,CAMAjf,eAAekQ,gCAAgCtC,EAAc9J,GACzD,IAAMub,EAAiBL,iBAAiBpR,CAAY,EACpDjN,IAAIoB,EAAS,CAAA,EACb,GAAI,CAACsd,EACD,MAAO,CAAA,EAEX,IAAK1e,IAAIoU,EAAI,EAAGA,EAAIsK,EAAe5Y,OAAQsO,CAAC,GAAI,CAC5C,IAIcuK,EAJRC,EAAgBF,EAAetK,GACR,UAAzB,OAAOwK,IACDC,EAAmBxe,MAAMyG,oBAAoB3D,EAAQ,CAACyb,EAAc,GACtD1Z,UAGkBzF,KAAAA,KAF5Bkf,EAAcE,EAAgB3Z,SAAS,IAE7B8R,eACZ2H,EAAY3H,gBAAkB9U,aAAaC,QAAQ,iBAAiB,GAClC,cAAlCwc,EAAYzH,oBAEZ4H,gCAAgCF,CAAa,EAC7Cxd,EAAS,CAAA,EAIzB,CACA,OAAOA,CACX,CAOA,SAAS2d,mBAAmB/L,GACxB,MAAO,CAAA,CACX,CAQA,SAAS5I,WAAW4U,EAAMC,EAAU,CAAA,GAChCjf,IAAIkf,EAAc,CACdjL,EAAG,CAAA,EACHC,EAAG,CAAA,EACHE,EAAG,CAAA,EACH+K,OAAQ,CAAA,EACRC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,EAAG,CAAA,EACHlJ,EAAG,CAAA,EACHmJ,GAAI,CAAA,EACJC,KAAM,CAAA,EACNC,WAAY,CAAA,EAQZA,WAAY,CAAA,EAPZC,IAAK,CAAA,EAQLA,IAAK,CAAA,EAPLC,IAAK,CAAA,EACLC,IAAK,CAAA,EACLrH,MAAO,CAAA,EACPsH,MAAO,CAAA,EACPhI,SAAU,CAAA,EACViI,OAAQ,CAAA,EAGRC,QAAS,CAAA,EACTC,QAAS,CAAA,CACb,EACIC,EAAe,CACflM,EAAG,CAAC,OAAQ,QAAS,SAAU,MAAO,QAAS,SAC/CyL,KAAM,CAAC,QAAS,QAAS,MACzBF,EAAG,CAAC,QAAS,SACbK,IAAK,CAAC,QAAS,QAAS,KAAM,iBAAkB,gBAChDC,IAAK,CAAC,MAAO,MAAO,QAAS,QAAS,QAAS,QAAS,UACxDrH,MAAO,CAAC,OAAQ,QAAS,QAAS,KAAM,WAAY,SAAU,SAC9DsH,MAAO,CAAC,MAAO,QAAS,SACxBhI,SAAU,CAAC,QAAS,KAAM,QAAS,OAAQ,OAAQ,WAAY,WAAY,QAC3EiI,OAAQ,CAAC,OAAQ,QAAS,QAAS,MACnCC,QAAS,CAAC,QAAS,QAAS,QAC5BC,QAAS,CAAC,QAAS,QACvB,EAEIjB,GAAgC,gBAArBA,EAAQlF,WACnBmF,EAAc,CAAE,GAAGA,EAAaO,GAAI,CAAA,CAAM,GAI9C,IAAMW,GADS,IAAIC,WACAC,gBAAgBtB,EAAM,WAAW,EAwDpD,MADA,CAAC,GAAGoB,EAAI7f,KAAKggB,YAAY9G,QAtDzB,SAAS+G,EAAMrD,GACX,GAAIA,EAAKC,WAAaC,KAAKC,aAAc,CACrC,IAAMmD,EAAMtD,EAAKuD,QAAQC,YAAY,EAErC,GAAI1B,EAAS,CAGL,IAGU2B,EAkBA/Q,EACAgR,EACAD,EAzBd,GAAI1B,EAAYuB,IAEA,QAARA,GAAsC,+BAArBxB,EAAQlF,UAA6CkF,EAAQ5E,UAc9E,OAbMxK,EAAMsN,EAAKzD,aAAa,KAAK,GAAK,GAClCmH,EAAM1D,EAAKzD,aAAa,KAAK,GAAK,WAClCkH,EAAOR,EAAI9O,cAAc,GAAG,GAC7B/J,KAAOsI,EACZ+Q,EAAKE,OAAS,SACdF,EAAKrP,UAAY,gCACXuO,EAAMM,EAAI9O,cAAc,KAAK,GAC/BzB,IAAMA,EACViQ,EAAIe,IAAMA,EACVf,EAAIvO,UAAY,8CAChBqP,EAAK9N,YAAYgN,CAAG,EACpB3C,EAAK4D,WAAWC,aAAaJ,EAAMzD,CAAI,EAJvC2C,KAKA3C,EAAK7S,OAAO,EAKpB,GAAI,CAAC4U,EAAYuB,GAYb,MAVY,QAARA,GAAsC,gBAArBxB,EAAQlF,UAA8BkF,EAAQ5E,YACzDxK,EAAMsN,EAAKzD,aAAa,KAAK,GAAK,GAClCmH,EAAM1D,EAAKzD,aAAa,KAAK,GAAK,WAClCkH,EAAOR,EAAI9O,cAAc,GAAG,GAC7B/J,KAAOsI,EACZ+Q,EAAKE,OAAS,SACdF,EAAKK,YAAcJ,EACnB1D,EAAK4D,WAAWC,aAAaJ,EAAMzD,CAAI,GAP3C,KASAA,EAAK7S,OAAO,CAGpB,CAGA,CAAC,GAAG6S,EAAK+D,YAAYzH,QAAQ0H,IACzB,IAAMC,EAAWD,EAAK/e,KAAKue,YAAY,EAClCR,EAAaM,IAAMvY,SAASkZ,CAAQ,GACrCA,CAAAA,EAASC,WAAW,IAAI,GACxBF,CAAAA,EAAK9Q,MAAMsQ,YAAY,EAAEzY,SAAS,aAAa,GAC/CiV,EAAK1L,gBAAgB0P,EAAK/e,IAAI,CAEtC,CAAC,CACL,CAEA,CAAC,GAAG+a,EAAKoD,YAAY9G,QAAQ+G,CAAK,CACtC,CACsC,EAC/BJ,EAAI7f,KAAKiR,SACpB,CAtX4B,YAAxBvH,SAASqX,WACTrX,SAASkC,iBAAiB,gBAAiB6Q,WAAW,EAEtD/S,SAASkC,iBAAiB,mBAAoB6Q,WAAW,EAQ7D/S,SAASkC,iBAAiB,kBAAmB,SAASuG,GAGlD,IAKM6O,EALF7O,EAAEoO,SAAW7W,WAIXuX,EAA2B,CAAC,CAAEvX,SAASyT,uBAAuB,aAAa,EAAE,IAC7E6D,EAAMtX,SAASgJ,aAAa,IAEF,KAAnBsO,EAAI1Y,SAAS,GAAa2Y,CAAAA,GAKnC3E,yBACAtQ,aAAasQ,uBAAuB,EAGxCA,wBAA0BxQ,WAAW,KACjC,IAMQoV,EAIEhb,EAVJuM,EAAY3L,OAAO4L,aAAa,EAEf,UAAnBD,EAAU5F,OAGNsU,EAAa1O,EAAU0O,WACvBD,EAAYzO,EAAUyO,UACtBvE,sBAAsBwE,CAAU,GAAKxE,sBAAsBuE,CAAS,IAGlEhb,EAAe4M,uBAAuBL,CAAS,IAIjDW,kBAAkBlN,EAAc,aAAa,EAGzD,EAAGsW,kBAAkB,GA1BjB,IAAIlQ,uBAAuB,GAAI,MAAM,EA2B7C,CAAC,EA8UD,IAAM8U,4BAA8B,OAC9BC,2BAA6B,QAC7BC,+BAAiC,UAOvC,SAASC,wBAAwB9O,GAC7B,IAAM+O,EAAQ/O,EAAUgP,WAAW,CAAC,EAC9BC,EAAiBF,EAAMG,wBAG7B,OAAIC,wBAAwBnP,CAAS,EAC1B4O,2BAIPK,EAAe7E,WAAaC,KAAKC,cACE,EAAnC2E,EAAe1B,WAAWza,QACE,KAA5Bic,EAAMlZ,SAAS,EAAEe,KAAK,GACtBmY,EAAMK,iBAAmBL,EAAMM,cAC/BN,EAAMK,eAAehF,WAAaC,KAAKC,aAChCuE,gCAILS,EAAkD,EAAjCP,EAAMlZ,SAAS,EAAEe,KAAK,EAAE9D,OACzCyc,EAAaN,EAAe7E,WAAaC,KAAKmF,UAC9CC,EAAcV,EAAMW,UAEtBJ,CAAAA,GAAmBC,CAAAA,GAAeE,EAI/B,KAHId,4BAIf,CAOA,SAAStO,uBAAuBL,GAG5B,GAAI,CAACA,EAA0F,OAA9EwK,gBAAgB,2DAA2D,EAAU,KAEtG,GAA6B,IAAzBxK,EAAU2P,WAA8F,OAA1EnF,gBAAgB,uDAAuD,EAAU,KAEnH,GAA2B,EAAvBxK,EAAU2P,WAAiG,OAA/EnF,gBAAgB,4DAA4D,EAAU,KAEtH,IAAMuE,EAAQ/O,EAAUgP,WAAW,CAAC,EAEpC,GAAID,EAAMK,iBAAmBL,EAAMM,aAA2G,OAA3F7E,gBAAgB,wEAAwE,EAAU,KAGrJ,IAAMoF,EAAgBd,wBAAwB9O,CAAS,EAGvD,GAAI,CAAC4P,EAAsG,OAArFpF,gBAAgB,kEAAkE,EAAU,KAGlHxd,IAAIuG,EAAe,GACfsc,EAAsB,EACtBC,EAAoB,EACpBxP,EAAW,GACftT,IAEM+iB,EAAahB,EAAMG,wBAEzB,OAAQU,GACJ,KAAKjB,4BACD,GAAuC,IAAnCI,EAAMlZ,SAAS,EAAEe,KAAK,EAAE9D,OAExB,OADA0X,gBAAgB,4DAA4D,EACrE,KAEX,IAAMwF,EAAoBD,EAAW3F,WAAaC,KAAKC,aAAeyF,EAAaA,EAAWxF,cAC9FhX,EAAewb,EAAMlZ,SAAS,EAC9Bga,EAAsBd,EAAMkB,YAC5BH,EAAoBf,EAAMmB,UACG,IAAxBL,GAA6Btc,EAAaT,OAASgd,IACpDA,EAAoBvc,EAAaT,QAErCwN,EAAW6P,yBAAyBH,CAAiB,EACrD,MAEJ,KAAKpB,2BACD,IAAMwB,EAAarB,EAAMK,eACnBiB,EAAgBlB,wBAAwBnP,CAAS,EACvDzM,YAAyB8c,EAAcxC,KAA0B,oBACjEvN,EAAW6P,yBAAyBE,CAAa,EAEjDR,EAAsBrQ,MAAM8Q,KAAKF,EAAWrC,WAAWwC,QAAQ,EAAEC,QAAQJ,CAAU,EACnFN,EAAoBD,EAAsB,EAC1C,MAEJ,KAAKhB,+BACK1Y,EAAU4Z,EAAW3F,WAAaC,KAAKC,aAAeyF,EAAaA,EAAWxF,cACpF,GAAIpU,EAAQoX,WAAWza,QAAU,EAE7B,OADA0X,gBAAgB,kEAAkE,EAC3E,KAEXjX,EAAe4C,EAAQ8X,aAAe,GACtC3N,EAAW6P,yBAAyBha,CAAO,EAE3C0Z,EAAsBrQ,MAAM8Q,KAAKna,EAAQ4X,WAAWwC,QAAQ,EAAEC,QAAQra,CAAO,EAC7E2Z,EAAoBD,EAAsB,CAElD,CAGA,IAAMhf,EAAUwD,OAAOC,SAASC,KAEhC,MAAO,CACHsb,oBAAAA,EACAC,kBAAAA,EACAvc,aAAcA,EAAaqD,KAAK,EAChC/F,QAAAA,EACAyP,SAAAA,EACAsP,cAAAA,EACAa,UAA4B7B,2BAtDjB,GAuDf,CACJ,CAOA,SAAS3L,yBAAyBpC,EAAsB6P,GAEpD,GAAoC,IAAhC7P,EAAqB/N,OAAzB,CAEA,IAAM6d,EAAc,IAAIC,IAGxB/P,EAAqB4F,QAAQoK,IAEzB,IAWM1a,EAXD0a,GAAMvQ,UAAad,MAAMC,QAAQoR,GAAMvQ,QAAQ,EAM/CjG,KAAKyW,uBAAuBD,EAAKvQ,QAAQ,GAKxCnK,EAAU4a,4BAA4BF,EAAKvQ,QAAQ,GAMlDuQ,EAAKjB,cASRiB,EAAKjB,eACL,CAAC,CACGjB,4BACAC,2BACAC,gCACF3Z,SAAS2b,EAAKjB,aAAa,EAE7BpF,gBAAgB,2BAA6BqG,EAAKjB,aAAa,GAI9De,EAAYK,IAAI7a,CAAO,GACxBwa,EAAYM,IAAI9a,EAAS,EAAE,EAE/Bwa,EAAY/U,IAAIzF,CAAO,EAAE0C,KAAKgY,CAAI,GApB9BrG,gBAAgB,iCAAiC,EAPjDA,gBAAgB,+BAAiCqG,EAAKvQ,QAAQ,EAN9DkK,gBAAgB,4BAA8BqG,EAAKvQ,QAAQ,EAN3DkK,gBAAgB,8CAAgDqG,CAAI,CAwC5E,CAAC,EAEDF,EAAYlK,QAAQ,CAACyK,EAAO/a,KACxB,IAAMyZ,EAAgBsB,EAAM,GAAGtB,cAG/B,OAAQA,GACJ,IAAK,QACDvV,KAAK8W,6BAA6Bhb,CAAO,EACzC,MAEJ,IAAK,UACDkE,KAAK+W,8BAA8Bjb,CAAO,EAC1C,MAEJ,IAAK,OACDkE,KAAKgX,8BAA8Blb,EAAS+a,EAAOR,CAAc,EACjE,MAEJ,QACIlG,gBAAgB,2BAA6BoF,CAAa,CAClE,CACJ,CAAC,CAtE4C,CAuEjD,CAMA,SAASuB,6BAA6Bhb,GACV,QAApBA,EAAQuX,QACRlD,gBAAgB,kDAAoDrU,EAAQuX,OAAO,EAGvFvX,EAAQkB,UAAU8I,IAAI,qCAAqC,CAC/D,CAMA,SAASiR,8BAA8Bjb,GACnCA,EAAQkB,UAAU8I,IAAI,uCAAuC,CACjE,CAQA,SAASkR,8BAA8Blb,EAAS+a,EAAMR,GAClD1jB,IAAIskB,EAAmB,GAevB,IAAMC;;;uCAbFD,EADAJ,EAAM,GAAG1P,QACU,4BAEA;2IAOgH0P,EAAM,GAAGvhB;;yCAO5I6hB,EAAOrb,EAAQ8X,YACnB,IAAMwD,EAAmBP,EAAM,GAAG3d,aAGlC,GAAOke,EAAP,CAKA,IAAMC,EAAU,GAiBhB,GAdAR,EAAMzK,QAAQoK,IAEV,IAAMc,EAAWC,SAASf,EAAKhB,mBAAmB,GAAK,EACjDgC,EAASD,SAASf,EAAKf,iBAAiB,GAAK,EAE/C6B,EAAW,GAAKE,EAASL,EAAK1e,QAAqB+e,EAAXF,EACxCnH,gBAAgB,2BAA6BqG,CAAI,GAIrDa,EAAQ7Y,KAAK,CAAEiZ,SAAUH,EAAUvX,KAAM,OAAQ,CAAC,EAClDsX,EAAQ7Y,KAAK,CAAEiZ,SAAUD,EAAQzX,KAAM,KAAM,CAAC,EAClD,CAAC,EAEsB,IAAnBsX,EAAQ5e,OAOZ,GAJA4e,EAAQ1Q,KAAK,CAACC,EAAGC,IAAMA,EAAE4Q,SAAW7Q,EAAE6Q,QAAQ,EAIzCN,EAAKO,MAAML,EAAQ,GAAGI,SAAUJ,EAAQ,GAAGI,QAAQ,IAAML,EAC1DjH,gBAAgB,4DAA4D,MADhF,CAKAxd,IAAIoB,EAASojB,EACbE,EAAQjL,QAAQuL,IACZ,IAAMC,EAA6B,UAAhBD,EAAO5X,KACpBmX,EA3CoB,UA8C1BnjB,EAASA,EAAO2jB,MAAM,EAAGC,EAAOF,QAAQ,EAAIG,EAAa7jB,EAAO2jB,MAAMC,EAAOF,QAAQ,CACzF,CAAC,EAGD,IACI3b,EAAQqI,UAAYpH,WAAWhJ,CAAM,EACrC6I,SAASuP,iBAAiB,+BAA+B,EAAEC,QAAQmH,IAC/DA,EAAKzU,iBAAiB,QAAS,IAE3BuG,EAAE8F,eAAe,EAEX0M,EADYtE,EAAKrP,UAAU7F,MAAM,GAAG,EAChB1E,KAAKme,GAAOA,EAAIjd,SAAS,YAAY,CAAC,EAChElI,IAAI2C,EAAS,MAETA,EADAuiB,EACSA,EAAQxZ,MAAM,YAAY,EAAE,GAErC/I,KACA+gB,EAAe3c,oBAAsBpE,EACrC+gB,EAAe/J,YAAY,EAEnC,CAAC,CACL,CAAC,CAGL,CAFE,MAAOxZ,GACLqd,gBAAgB,mCAAqCrd,CAAK,CAC9D,CAhCA,CA7BA,MAFIqd,gBAAgB,+BAA+B,CAgEvD,CAOA,SAASpK,wBAAwBgS,GACvBjI,EAAO4G,4BAA4BqB,CAAI,EAC7C,MAAA,EAAIjI,CAAAA,GAAQA,CAAAA,EAAKkI,iBACblI,EAAKkI,eAAe,CAAEhN,SAAU,SAAUiN,MAAO,QAAS,CAAC,EACpD,GAGf,CAEA,SAASvS,0BACL,IACMwS,EAAQtb,SAASuP,iBAAiB,qCAA4B,EACpE,IAAMgM,EAAkB,IAAIC,IAkBtBC,GAhBNH,EAAM9L,QAAQiG,IACV,IAAMiG,EAASjG,EAAKqB,WAEd6E,GADNJ,EAAgBrS,IAAIwS,CAAM,EACVjG,EAAKxV,cAAc,6CAA6C,GAIhF,IAHI0b,GAASA,EAAQtb,OAAO,EAGrBoV,EAAKmG,YACRF,EAAO3E,aAAatB,EAAKmG,WAAYnG,CAAI,EAE7CiG,EAAOG,YAAYpG,CAAI,CAC3B,CAAC,EAGD8F,EAAgB/L,QAAQkM,GAAUA,EAAOI,UAAU,CAAC,EAElB,yCAK5BC,GAJW/b,SAASuP,iBAAiB,IAAIkM,CAA2B,EACjEjM,QAAQtQ,IACbA,EAAQkB,UAAUC,OAAOob,CAAyB,CACtD,CAAC,EAC+B,uCACjBzb,SAASuP,iBAAiB,IAAIwM,CAAyB,EAC/DvM,QAAQtQ,IACXA,EAAQkB,UAAUC,OAAO0b,CAAuB,CACpD,CAAC,CACL,CAOA,SAASlC,uBAAuBxQ,GAC5B,MAAKd,CAAAA,CAAAA,MAAMC,QAAQa,CAAQ,GACH,IAApBA,EAASxN,QAENwN,EAAS2S,MAAMC,GACXnP,OAAOoP,UAAUD,CAAK,GAAc,GAATA,GAAcA,EAAQ,GAC3D,CACL,CAOA,SAAS/D,wBAAwBnP,GAE7B,GAAKA,GAAsC,IAAzBA,EAAU2P,YAAoB3P,CAAAA,EAAUyP,YAA1D,CAIA,IAAMV,EAAQ/O,EAAUgP,WAAW,CAAC,EAGpC,GAAID,EAAMK,iBAAmBL,EAAMM,cAC/BN,EAAMK,eAAehF,WAAaC,KAAKC,cACN,QAAjCyE,EAAMK,eAAe1B,QACrB,OAAOqB,EAAMK,eAiBbgE,EAbWnc,SAASoc,iBACpBtE,EAAMG,wBACNoE,WAAWC,aACX,CACIC,WAAY,SAASrJ,GACjB,MAAwB,QAAjBA,EAAKuD,SACZ+F,wBAAwBtJ,EAAM4E,CAAK,EAC/BuE,WAAWI,cACXJ,WAAWK,aACnB,CACJ,CACJ,EAEqBC,SAAS,EAC9B,GAAIR,EACA,OAAOA,EAIX,IAgBWjd,EAhBL0d,EAAeC,0BAA0B/E,EAAMK,cAAc,EAC7D2E,EAAaD,0BAA0B/E,EAAMM,YAAY,EAG/D,GAAIwE,GAAyC,QAAzBA,EAAanG,SAC7BsG,kCAAkCH,EAAc9E,CAAK,EACrD,OAAO8E,EAGX,GAAIE,GAAqC,QAAvBA,EAAWrG,SACzBsG,kCAAkCD,EAAYhF,CAAK,EACnD,OAAOgF,EAKX,IAAW5d,KADY8d,0BAA0BlF,CAAK,EAElD,GAAwB,QAApB5Y,EAAQuX,QACR,OAAOvX,CAjDf,CAqDA,OAAO,IACX,CAEA,SAASsd,wBAAwBtd,EAAS4Y,GACtC,IAAMmF,EAAejd,SAASkd,YAAY,EAE1C,OADAD,EAAaE,WAAWje,CAAO,EACxB4Y,EAAMsF,sBAAsBC,MAAMC,eAAgBL,CAAY,GAAK,GACP,GAA/DnF,EAAMsF,sBAAsBC,MAAME,WAAYN,CAAY,CAClE,CAEA,SAASF,kCAAkC7d,EAAS4Y,GAC1C0F,EAActe,EAAQmT,sBAAsB,EAC5CoL,EAAY3F,EAAMzF,sBAAsB,EAG9C,MAAO,EAAEmL,EAAYE,MAAQD,EAAUE,MACnCH,EAAYG,KAAOF,EAAUC,OAC7BF,EAAYhL,OAASiL,EAAUvP,KAC/BsP,EAAYtP,IAAMuP,EAAUjL,OACpC,CAEA,SAASqK,0BAA0B3J,GAC/B,OAAOA,EAAKC,WAAaC,KAAKC,aAAeH,EAAOA,EAAKI,aAC7D,CAOA,SAAS0J,0BAA0BlF,GAC/B,IAAM8F,EAAW,GACXC,EAAY/F,EAAMG,wBAGlB6F,EAAkBD,EAAUE,uBAC5BC,EAAcH,EAAUI,mBAU9B,GARIH,GACAF,EAAShc,KAAKkc,CAAe,EAE7BE,GACAJ,EAAShc,KAAKoc,CAAW,EAIzBH,EAAU1K,WAAaC,KAAKC,aAAc,CAC1C,IAAMiG,EAAWuE,EAAUvE,SAC3B,IAAKvjB,IAAIoU,EAAI,EAAGA,EAAImP,EAASzd,OAAQsO,CAAC,GAC9B4S,kCAAkCzD,EAASnP,GAAI2N,CAAK,GACpD8F,EAAShc,KAAK0X,EAASnP,EAAE,CAGrC,CAEA,OAAOyT,CACX,CAQA,SAAS1E,yBAAyBhG,GAE9B,IADAnd,IAAIolB,EAAO,GACJjI,GAAM,CACTnd,IAAIkmB,EAAQ,EACRiC,EAAUhL,EAAKiL,gBACnB,KAAOD,GACsB,IAArBA,EAAQ/K,UACR8I,CAAK,GAETiC,EAAUA,EAAQC,gBAEtBhD,EAAKiD,QAAQnC,CAAK,EAClB/I,EAAOA,EAAK4D,UAChB,CAKA,OAFAqE,EAAKkD,MAAM,EAEJlD,CACX,CAQA,SAASrB,4BAA4BqB,GAEjC,GAAK,CAAEA,EACH,OAAO,KAGXplB,IAAImd,EAAOlT,SACX,IAAKjK,IAAIoU,EAAI,EAAGA,EAAIgR,EAAKtf,OAAQsO,CAAC,GAE9B,GAAK,EADL+I,EAAOA,EAAKoG,SAAS6B,EAAKhR,KAEtB,OAAO,KAGf,OAAO+I,CACX,CAEAnd,IAAIuoB,k9vBAKJ,SAAStW,2BACL,MAA4D,MAArD/P,aAAaC,QAAQ,0BAA0B,CAC1D,CAMA,SAASsN,0BACL,OAA4D,OAArDvN,aAAaC,QAAQ,0BAA0B,CAC1D,CAMA,SAAS2M,yBAAyB0Z,GAC9BtmB,aAAa8D,QAAQ,2BAA4BwiB,EAAU,IAAM,GAAG,CACxE,CAMA,SAASxW,0BACL,OAAmD,OAA5C9P,aAAaC,QAAQ,iBAAiB,CACjD,CAMA,SAASqN,2BAA2BlL,GAChC,GAAKA,GAAUkO,MAAMC,QAAQnO,CAAK,EAAlC,CAIAtE,IAAIyoB,EAAc,GAClB,IACIA,EAAcpiB,KAAKC,MAAMpE,aAAaC,QAAQ,sBAAsB,GAAK,IAAI,CAGjF,CAFE,MAAOhC,GACLsoB,EAAc,EAClB,CAEAnkB,EAAMmV,QAAQjV,IACNA,EAAK7B,QAAU6B,EAAKC,iBACpBgkB,EAAYjkB,EAAK7B,QAAU,CACvBA,OAAQ6B,EAAK7B,OACb8B,eAAgBD,EAAKC,cACzB,EAER,CAAC,EAEDvC,aAAa8D,QAAQ,uBAAwBK,KAAKK,UAAU+hB,CAAW,CAAC,CAlBxE,CAmBJ,CAEA,SAASzjB,sBAAsBV,GACtBA,GAAUkO,MAAMC,QAAQnO,CAAK,IAI5BokB,EAAQpkB,EAAMsD,OAAOpD,GAChBA,EAAK/B,QACf,GAAGqD,OAEJ5D,aAAa8D,QAAQ,sBAAuB,GAAG0iB,CAAO,EAC1D,CAQA,SAASjK,uBAAuB9b,EAAQgmB,GACpC,GAAI,CAAChmB,GAAU,CAACgmB,EACZ,OAAO,KAGX3oB,IAAIyoB,EAAc,GAClB,IACIA,EAAcpiB,KAAKC,MAAMpE,aAAaC,QAAQ,sBAAsB,GAAK,IAAI,CAGjF,CAFE,MAAOhC,GACLsoB,EAAc,EAClB,CACMG,EAAaH,EAAY9lB,GAE/B,MAAKimB,CAAAA,CAAAA,GAIgB,IAAIzgB,KAAKygB,EAAWnkB,cAAc,EACjC,IAAI0D,KAAKwgB,CAAiB,CAEpD,CAMA,SAAS7J,gCAAgCnc,GACrC,GAAKA,EAAL,CAIA3C,IAAI6oB,EAAe,GACnB,IACIA,EAAexiB,KAAKC,MAAMpE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACL0oB,EAAe,EACnB,CAEKA,EAAa3gB,SAASvF,CAAM,GAC7BkmB,EAAahd,KAAKlJ,CAAM,EAG5BT,aAAa8D,QAAQ,yBAA0BK,KAAKK,UAAUmiB,CAAY,CAAC,CAb3E,CAcJ,CAMA,SAAShS,mCAAmClU,GACxC,GAAKA,EAAL,CAIA3C,IAAI6oB,EAAe,GACnB,IACIA,EAAexiB,KAAKC,MAAMpE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACL0oB,EAAe,EACnB,CACAA,EAAeA,EAAajhB,OAAOkhB,GAAMA,IAAOnmB,CAAM,EACtDT,aAAa8D,QAAQ,yBAA0BK,KAAKK,UAAUmiB,CAAY,CAAC,CAT3E,CAUJ,CAMA,SAASvZ,+BACLtP,IAAI6oB,EAAe,GACnB,IACIA,EAAexiB,KAAKC,MAAMpE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACL0oB,EAAe,EACnB,CAEA,OAA6B,EAAtBA,EAAa/iB,MACxB,CAOA,SAASiQ,oCAAoCpT,GACzC,GAAI,CAACA,EACD,MAAO,CAAA,EAGX3C,IAAI6oB,EAAe,GACnB,IACIA,EAAexiB,KAAKC,MAAMpE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACL0oB,EAAe,EACnB,CAEA,OAAOA,EAAa3gB,SAASvF,EAAOkG,SAAS,CAAC,CAClD,OAMMwF,aAKFlB,YAAY4b,GAER1b,KAAK2b,MAAQ,GAGb3b,KAAK4b,YAAc,QAGnB5b,KAAK6b,aAAe,SAGpB7b,KAAK8b,SAAW,EAGhB9b,KAAK+b,aAAe,CAAC,aAAc,YAAa,YAAa,kBAAmB,aAAc,sBAG9F/b,KAAK0b,kBAAoBA,EAGzB1b,KAAKgc,WAAa,CAAC,QAAS,KAAM,KAAM,KAC5C,CAMA/b,OACID,KAAKic,mBAAmB,EACxBjc,KAAKkc,qBAAqB,CAC9B,CAMAD,qBAEIjc,KAAKmc,UAAYvf,SAASM,eAAe,qDAAqD,EAG9F8C,KAAKoc,SAAWxf,SAASM,eAAe,6CAA6C,EAErF8C,KAAKqc,gBAAkBzf,SAASM,eAAe,2CAA2C,EAG1F8C,KAAKvM,aAAemJ,SAASM,eAAe,yCAAyC,EAEhF8C,KAAKmc,WAAcnc,KAAKoc,UAAapc,KAAKvM,cAAgBuM,CAAAA,KAAKqc,iBAChEzQ,QAAQ0Q,KAAK,kCAAkC,CAEvD,CAMAJ,uBACQlc,KAAKmc,WACLnc,KAAKmc,UAAUrd,iBAAiB,SAAU,GAAOkB,KAAKuc,sBAAsBlX,CAAC,CAAC,CAEtF,CAOA4G,oBAAoBnQ,GAChBA,EAAQgD,iBAAiB,QAAS,IAC9BuG,EAAE8F,eAAe,EACbnL,KAAKmc,WACLnc,KAAKmc,UAAUK,MAAM,CAE7B,CAAC,CACL,CAOAD,sBAAsBE,GAClBzc,KAAK0c,WAAW,EAEhB,IAAMC,EAAgBxX,MAAM8Q,KAAKwG,EAAMhJ,OAAOkI,KAAK,EAC/C3b,KAAK2b,MAAMljB,OAASkkB,EAAclkB,OAASuH,KAAK8b,SAChD9b,KAAK0L,qBAAqB1L,KAAK8b,iCAAiC,GAGjDa,EAAcpiB,OAAOrE,GAAQ8J,KAAK4c,aAAa1mB,CAAI,CAAC,EAE5DkW,QAAQlW,GAAQ8J,KAAK6c,QAAQ3mB,CAAI,CAAC,EAG7CumB,EAAMhJ,OAAOzQ,MAAQ,GAGrBhD,KAAKqc,gBAAgBhd,MAAMC,QAAU,QACzC,CAOAsd,aAAa1mB,GAET,OAAIA,EAAK4mB,KAAO9c,KAAK4b,aACjB5b,KAAK0L,mBAAmBxV,EAAKnB,qCAAqCiL,KAAK+c,eAAe/c,KAAK4b,WAAW,CAAG,EAClG,CAAA,GAIO5b,KAAKgd,aAAa,EAAI9mB,EAAK4mB,KAC7B9c,KAAK6b,cACjB7b,KAAK0L,UAAU,uCAAuC1L,KAAK+c,eAAe/c,KAAK6b,YAAY,CAAG,EACvF,CAAA,GAIX,EAA+B,EAA3B7b,KAAK+b,aAAatjB,QAAeuH,CAAAA,KAAK+b,aAAalhB,SAAS3E,EAAK6J,IAAI,IACrEC,KAAK0L,wBAAwBxV,EAAK6J,cAAc7J,EAAKnB,yBAAyB,EACvE,GAIf,CAMAioB,eACI,OAAOhd,KAAK2b,MAAMsB,OAAO,CAACC,EAAKrnB,IAAaqnB,EAAMrnB,EAASK,KAAK4mB,KAAM,CAAC,CAC3E,CAOAD,QAAQ3mB,GACEinB,EAAa,CACf1B,GAAIzb,KAAKod,eAAe,EACxBlnB,KAAMA,CACV,EAEA8J,KAAK2b,MAAMnd,KAAK2e,CAAU,EAC1Bnd,KAAKqd,eAAe,CACxB,CAOAD,iBACI,OAAOtiB,KAAKwiB,IAAI,EAAIC,KAAKC,OAAO,EAAEhiB,SAAS,EAAE,EAAEiiB,OAAO,EAAG,CAAC,CAC9D,CAOAC,WAAWC,GACP3d,KAAK2b,MAAQ3b,KAAK2b,MAAMphB,OAAOqjB,GAAKA,EAAEnC,KAAOkC,CAAM,EACnD3d,KAAKqd,eAAe,EACpBrd,KAAK0c,WAAW,CACpB,CAMAW,iBACI,IAOMQ,EAPD7d,KAAKoc,WAEgB,IAAtBpc,KAAK2b,MAAMljB,OACXuH,KAAKoc,SAASjY,UAAYpH,WAAW,4EAA4E,GAI/G8gB,EAAY7d,KAAK2b,MAAMzkB,IAAIrB,GAAYmK,KAAK8d,eAAejoB,CAAQ,CAAC,EAC1EmK,KAAKoc,SAASjY,UAAYpH,WAAW,EAAE,EACvC8gB,EAAUzR,QAAQxS,GAAQoG,KAAKoc,SAAS3W,YAAY7L,CAAI,CAAC,GAC7D,CASAkkB,eAAejoB,GACX,GAAM,CAAEK,KAAAA,EAAMulB,GAAAA,CAAG,EAAI5lB,EACfkoB,EAAWnhB,SAASqH,cAAc,KAAK,EAgB7C,OAfA8Z,EAAS7Z,UAAY,8CAErB6Z,EAAS5Z,UAAYpH;;;+EAGkDiD,KAAK0b,kBAAkBtS,OAAOlT,EAAKnB,IAAI,CAAC;+EACxCiL,KAAK+c,eAAe7mB,EAAK4mB,IAAI;;;uGAGLrB;SAC9F,EAEiBsC,EAASlhB,cAAc,+CAA+C,EAC9EiC,iBAAiB,QAAS,IAAMkB,KAAK0d,WAAWjC,CAAE,CAAC,EAEtDsC,CACX,CAOAhB,eAAeiB,GACX,IAGMjX,EAHN,OAAc,IAAViX,EAAoB,WAGlBjX,EAAIwW,KAAKU,MAAMV,KAAK1R,IAAImS,CAAK,EAAIT,KAAK1R,IADlC,IACuC,CAAC,EAE3CqS,YAAYF,EAAQT,KAAKY,IAHtB,KAG6BpX,CAAC,GAAGqX,QAAQ,CAAC,CAAC,EAAI,IAAMpe,KAAKgc,WAAWjV,GACnF,CAOA2E,UAAUtY,GACF4M,KAAKvM,eACLuM,KAAKvM,aAAamgB,YAAcxgB,EAChC4M,KAAKvM,aAAa4L,MAAMC,QAAU,QAE1C,CAMAod,aACQ1c,KAAKvM,eACLuM,KAAKvM,aAAamgB,YAAc,GAChC5T,KAAKvM,aAAa4L,MAAMC,QAAU,OAE1C,CAMAiM,WACI,OAA2B,EAApBvL,KAAK2b,MAAMljB,MACtB,CAMA4lB,aACIre,KAAK2b,MAAQ,GACb3b,KAAKqd,eAAe,CACxB,CAeAiB,iBAAiBzoB,GACb,IAQW0oB,EAAX,IAAWA,IARS,CAChB,CAAEC,MAAO,YAAaze,KAAM,SAAU3M,QAAS,yBAA0B,EACzE,CAAEorB,MAAO,mBAAoBze,KAAM,SAAU3M,QAAS,4BAA6B,EACnF,CAAEorB,MAAO,sBAAuBze,KAAM,SAAU3M,QAAS,+BAAgC,EACzF,CAAEorB,MAAO,YAAaze,KAAM,SAAU3M,QAAS,2BAA4B,EAC3E,CAAEorB,MAAO,WAAYze,KAAM,SAAU3M,QAAS,0BAA2B,GAGvC,CAClC,IAAM4P,EAAQhD,KAAKye,eAAe5oB,EAAU0oB,EAAWC,KAAK,EAC5D,GAAI,CAACxb,GAAS,OAAOA,IAAUub,EAAWxe,KACtC,MAAM,IAAI1N,MAAMksB,EAAWnrB,OAAO,CAE1C,CAEA,GAAKyC,EAASM,YAAgBN,EAASM,sBAAsBuoB,KAI7D,OAAO7oB,EAHH,MAAM,IAAIxD,MAAM,6BAA6B,CAIrD,CASAosB,eAAeE,EAAK5G,GAChB,OAAOA,EAAK1Z,MAAM,GAAG,EAAE4e,OAAO,CAAC2B,EAAStsB,IAAQssB,IAAUtsB,GAAMqsB,CAAG,CACvE,CAOAE,2BAA2BhpB,GACjBipB,EAAoB9rB,MAAMgN,KAAKse,iBAAiBzoB,CAAQ,EAC9D,OAAaD,qBAAqBkpB,CAAiB,CACvD,CASArT,gCAAgC3V,EAAQ9B,EAAW0B,GAE/C,IAAMqpB,EAAU,CACZC,mBAAoBhf,KAAK2b,MAAMljB,OAC/BwmB,eAAgB,EAChBC,YAAa,GACb3mB,QAAS,CAAA,CACb,EAEA,IAAK5F,IAAIoU,EAAI,EAAGA,EAAI/G,KAAK2b,MAAMljB,OAAQsO,CAAC,GAAI,CACxC,IAAMlR,EAAWmK,KAAK2b,MAAM5U,GAEtBhT,EAAS,CACXwE,QAAS,CAAA,EACTxF,SAAU,KACVD,MAAO,IACX,EAEA,IACI,IAAMqsB,EAAiB,CACnBrpB,OAAAA,EACA9B,UAAAA,EACA0B,UAAAA,EACAO,SAAUJ,EAASK,KAAKnB,KACxBoB,WAAYN,EAASK,KACrBG,gBAAiB0Q,CACrB,EAEMhU,EAAWC,MAAMgN,KAAK6e,qBAAqBM,CAAc,EAC/DprB,EAAOhB,SAAWA,EAClBgB,EAAOwE,QAA8B,MAApBxF,EAAS0C,OAEtB1B,EAAOwE,SACPwmB,EAAQE,cAAc,EAI9B,CAFE,MAAOnsB,GACLiB,EAAOjB,MAAQA,EAAMM,OACzB,CAEA2rB,EAAQG,YAAY1gB,KAAKzK,CAAM,CACnC,CAKA,OAHAgrB,EAAQxmB,QAAUwmB,EAAQC,qBAAuBD,EAAQE,eACzDjf,KAAKqe,WAAW,EAETU,CACX,CACJ,OAEMpS,uBACFC,uBAAuBvI,GACnB,IAAM+a,EAAiBpf,KAAKqE,GAE5B,GAA8B,YAA1B,OAAO+a,EACP,MAAM,IAAI/sB,0BAA0BgS,cAAyB,EAKjE,OAFe+a,EAAeC,KAAKrf,IAAI,EAAEzD,KAAK,CAGlD,CAEA+iB,oBACI;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BJ,CAEAC,wBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDJ,CAEAC,oCACI;;;;;;CAOJ,CAEAC,iCACI;;;;;;;;;;CAWJ,CAEAC,sBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuEJ,CAEAC,qBACI;;;;;;;;;;;;;;;;;;;;;;;;;CA0BJ,CAEAC,mBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyDJ,CAEAC,cACI;;;;;OAMJ,CAEAC,qBACI;;;;UAKJ,CAEAC,mBACI,MAAO,0EACX,CACAC,uBACI,MAAO,sJACX,CAEJ,OAEM7f,iBACF8f,eAAeC,GACX,IAAMC,EAAYngB,KAAKkgB,GAEvB,GAAyB,YAArB,OAAOC,EACP,MAAM,IAAI9tB,0BAA0B6tB,cAAoB,EAG5D,OAAOC,EAAUd,KAAKrf,IAAI,EAAEzD,KAAK,CACrC,CAEA6jB,mBAAmBF,GACf,OAAOlgB,KAAKigB,QAAQC,CAAO,CAC/B,CAEA9f,oBAAoB8f,GACVG,EAAMrgB,KAAKigB,QAAQC,CAAO,EAChC,OAAOlgB,KAAKsgB,aAAaD,CAAG,CAChC,CAEAC,oBAAoBC,GACVvC,GAAQ,IAAIwC,aAAcC,OAAOF,CAAS,EAEhD,MAAO,6BADUG,KAAKtX,OAAOuX,aAAa,GAAG3C,CAAK,CAAC,CAEvD,CAEA1d,qBACI;;;OAIJ,CAEA2E,yBACI;;;OAIJ,CAEA/E,2BACI;;;;OAKJ,CAEAgF,+BACI;;;;OAKJ,CAEA1E,2BACI;;;;;;;;;;;;OAaJ,CAEAD,yBACI;;;OAIJ,CAEAE,0BACI;;;OAIJ,CAEAC,yBACI;;;;OAKJ,CAEAE,wBACI;;;OAIJ,CAEAC,yBACI;;;;;OAMJ,CAEAF,kCACI;;;OAIJ,CAEAG,uBACI;;;OAIJ,CAEAT,0BACI;;;;OAKJ,CAEAugB,oBACI;;;;;;;;;;;CAYJ,CAEA7b,iBACI;;;;CAKJ,CAEAC,kBACI;;;;CAKJ,CACJ,OAEM4K,qBAEF9P,cACIE,KAAK6gB,QAAQ,CACjB,CAEAC,aAEI,OAAO5F,UACX,CAEA2F,UACI7gB,KAAK+gB,UAAU,EACf/gB,KAAKghB,QAAQ,CACjB,CAEAD,YACI,IAAME,EAAmBrkB,SAASqH,cAAc,MAAM,EAKhDid,GAJND,EAAiBE,IAAM,aACvBF,EAAiB/mB,KAAO,+BACxB0C,SAASwkB,KAAK3b,YAAYwb,CAAgB,EAEhBrkB,SAASqH,cAAc,MAAM,GAMjDod,GALNH,EAAkBC,IAAM,aACxBD,EAAkBhnB,KAAO,4BACzBgnB,EAAkBI,YAAc,cAChC1kB,SAASwkB,KAAK3b,YAAYyb,CAAiB,EAE1BtkB,SAASqH,cAAc,MAAM,GAC9Cod,EAASF,IAAM,aACfE,EAASnnB,KAAO,2EAChB0C,SAASwkB,KAAK3b,YAAY4b,CAAQ,CACtC,CAEAL,UACI,IAAM3hB,EAAQzC,SAASqH,cAAc,OAAO,EAC5C5E,EAAMkiB,aAAa,KAAM,aAAa,EACtCliB,EAAMuU,YAAc5T,KAAK8gB,WAAW,EACpClkB,SAASwkB,KAAK3b,YAAYpG,CAAK,CACnC,CACJ,CAEAzC,SAAS4kB,cAAc,IAAIC,YAAY,gBAAiB,CACpDC,OAAQ,CACJppB,WAAW,IAAIwC,MAAO6mB,YAAY,EAClCvuB,QAAS,iCACb,CACJ,CAAC,CAAC"} \ 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 || '';\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\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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 jogoutUserDoboard(this.params.accountId);\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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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\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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:\"\";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`;\n/**\r\n * SELECTION will be grouped into three types:\r\n * 1 - Simple text within a single tag\r\n * 2 - Image tags\r\n * 3 - Any tag containing nested content\r\n * Each type will be processed differently.\r\n */\r\nconst SPOTFIX_SELECTION_TYPE_TEXT = 'text';\r\nconst SPOTFIX_SELECTION_TYPE_IMG = 'image';\r\nconst SPOTFIX_SELECTION_TYPE_ELEMENT = 'element';\r\n\r\n/**\r\n * Determines the type of selection\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {string|null} Selection type\r\n */\r\nfunction spotFixGetSelectionType(selection) {\r\n const range = selection.getRangeAt(0);\r\n const commonAncestor = range.commonAncestorContainer;\r\n\r\n // Case 1: Image selection\r\n if (spotFixGetSelectedImage(selection)) {\r\n return SPOTFIX_SELECTION_TYPE_IMG;\r\n }\r\n\r\n // Case 2: Element with nested content\r\n if (commonAncestor.nodeType === Node.ELEMENT_NODE &&\r\n commonAncestor.childNodes.length > 1 &&\r\n range.toString().trim() === '' &&\r\n range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE) {\r\n return SPOTFIX_SELECTION_TYPE_ELEMENT;\r\n }\r\n\r\n // Case 3: Simple text\r\n const hasTextContent = range.toString().trim().length > 0;\r\n const isTextNode = commonAncestor.nodeType === Node.TEXT_NODE;\r\n const isCollapsed = range.collapsed;\r\n\r\n if (hasTextContent && (isTextNode || !isCollapsed)) {\r\n return SPOTFIX_SELECTION_TYPE_TEXT;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extracts selection data from DOM Selection object\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {Object|null} Selection data with text, positions, URL and node path OR null (nothing)\r\n */\r\nfunction spotFixGetSelectedData(selection) {\r\n // Prechecks:\r\n // Selection not provided\r\n if (!selection) {spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection not provided`'); return null; }\r\n // Range not provided\r\n if (selection.rangeCount === 0) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Range not provided`'); return null; }\r\n // Several ranges provided\r\n if (selection.rangeCount > 1) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Several ranges provided`'); return null; }\r\n\r\n const range = selection.getRangeAt(0);\r\n // Selection must be within a single DOM element.\r\n if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }\r\n\r\n // FIRST - check selection type\r\n const selectionType = spotFixGetSelectionType(selection);\r\n\r\n // Selection type not determined\r\n if (!selectionType) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection type not determined`'); return null; }\r\n\r\n // SECOND - generate selectedData for each selectionType\r\n let selectedText = '';\r\n let startSelectPosition = 0;\r\n let endSelectPosition = 0;\r\n let nodePath = '';\r\n let imageUrl = '';\r\n\r\n const commonNode = range.commonAncestorContainer;\r\n\r\n switch (selectionType) {\r\n case SPOTFIX_SELECTION_TYPE_TEXT:\r\n if (range.toString().trim().length === 0) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection text is empty`');\r\n return null;\r\n }\r\n const commonNodeElement = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n selectedText = range.toString();\r\n startSelectPosition = range.startOffset;\r\n endSelectPosition = range.endOffset;\r\n if ( startSelectPosition === 0 && selectedText.length > endSelectPosition ) {\r\n endSelectPosition = selectedText.length;\r\n }\r\n nodePath = spotFixCalculateNodePath(commonNodeElement);\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_IMG:\r\n const imgElement = range.startContainer;\r\n const selectedImage = spotFixGetSelectedImage(selection);\r\n selectedText = `Image (${selectedImage.alt ? selectedImage.alt : 'no description'})`;\r\n nodePath = spotFixCalculateNodePath(selectedImage);\r\n // For images, positions represent the image element position in parent\r\n startSelectPosition = Array.from(imgElement.parentNode.children).indexOf(imgElement);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_ELEMENT:\r\n const element = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n if (element.childNodes.length <= 1) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection have not inner data`');\r\n return null;\r\n }\r\n selectedText = element.textContent || '';\r\n nodePath = spotFixCalculateNodePath(element);\r\n // For elements, positions represent the element's position in parent\r\n startSelectPosition = Array.from(element.parentNode.children).indexOf(element);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n }\r\n\r\n // Get page URL\r\n const pageURL = window.location.href;\r\n\r\n return {\r\n startSelectPosition,\r\n endSelectPosition,\r\n selectedText: selectedText.trim(),\r\n pageURL,\r\n nodePath,\r\n selectionType,\r\n imageUrl: selectionType === SPOTFIX_SELECTION_TYPE_IMG ? imageUrl : ''\r\n };\r\n}\r\n\r\n/**\r\n * Highlight elements.\r\n * @param {[object]} spotsToBeHighlighted\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightElements(spotsToBeHighlighted, widgetInstance) {\r\n\r\n if (spotsToBeHighlighted.length === 0) return;\r\n\r\n const elementsMap = new Map();\r\n\r\n // Grouping elements with validation\r\n spotsToBeHighlighted.forEach(spot => {\r\n // nodePath validating: is array\r\n if (!spot?.nodePath || !Array.isArray(spot?.nodePath)) {\r\n spotFixDebugLog('Invalid spot: missing or invalid nodePath: ' + spot);\r\n return;\r\n }\r\n\r\n // nodePath validating: is valid indexes list\r\n if (!this.spotFixIsValidNodePath(spot.nodePath)) {\r\n spotFixDebugLog('Invalid nodePath format: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n const element = spotFixRetrieveNodeFromPath(spot.nodePath);\r\n if (!element) {\r\n spotFixDebugLog('Element not found for path: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n if ( ! spot.selectionType ) {\r\n // @ToDo need to apply backward capability here\r\n // just `spot.selectionType = 'text';` is not able, this opens ability to unauthorized modify website content\r\n spotFixDebugLog('Selection type is not provided.');\r\n return;\r\n }\r\n\r\n // selectionType parameter validating\r\n if (\r\n spot.selectionType &&\r\n ![\r\n SPOTFIX_SELECTION_TYPE_TEXT,\r\n SPOTFIX_SELECTION_TYPE_IMG,\r\n SPOTFIX_SELECTION_TYPE_ELEMENT\r\n ].includes(spot.selectionType)\r\n ) {\r\n spotFixDebugLog('Invalid selection type: ' + spot.selectionType);\r\n return;\r\n }\r\n\r\n if (!elementsMap.has(element)) {\r\n elementsMap.set(element, []);\r\n }\r\n elementsMap.get(element).push(spot);\r\n });\r\n\r\n elementsMap.forEach((spots, element) => {\r\n const selectionType = spots[0].selectionType;\r\n\r\n // MAIN LOGIC: highlight for the different types\r\n switch (selectionType) {\r\n case 'image':\r\n this.spotFixHighlightImageElement(element);\r\n break;\r\n\r\n case 'element':\r\n this.spotFixHighlightNestedElement(element);\r\n break;\r\n\r\n case 'text':\r\n this.spotFixHighlightTextInElement(element, spots, widgetInstance);\r\n break;\r\n\r\n default:\r\n spotFixDebugLog('Unknown selection type: ' + selectionType);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Highlight image element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightImageElement(element) {\r\n if (element.tagName !== 'IMG') {\r\n spotFixDebugLog('Expected IMG element for image highlight, got: ' + element.tagName);\r\n return;\r\n }\r\n element.classList.add('doboard_task_widget-image_selection');\r\n}\r\n\r\n/**\r\n * Highlight nested element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightNestedElement(element) {\r\n element.classList.add('doboard_task_widget-element_selection');\r\n}\r\n\r\n/**\r\n * Highlight text in element with span wrapping\r\n * @param {Element} element\r\n * @param {Array} spots\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightTextInElement(element, spots,widgetInstance) {\r\n let tooltipTitleText = '';\r\n if (spots[0].isFixed) {\r\n tooltipTitleText = `This issue already fixed.`;\r\n } else {\r\n tooltipTitleText = `We are already working on this issue.`;\r\n }\r\n\r\n const tooltip = `
\r\n \r\n \r\n
${tooltipTitleText}
\r\n
You can see history Here
\r\n
\r\n
`;\r\n\r\n const spotfixHighlightOpen = `${tooltip}`;\r\n const spotfixHighlightClose = ``;\r\n\r\n let text = element.textContent;\r\n const spotSelectedText = spots[0].selectedText;\r\n\r\n // meta.selectedText can not be empty string\r\n if ( ! spotSelectedText ) {\r\n spotFixDebugLog('Provided metadata is invalid.');\r\n return;\r\n }\r\n\r\n const markers = [];\r\n\r\n // Mark positions for inserting\r\n spots.forEach(spot => {\r\n // Validating positions\r\n const startPos = parseInt(spot.startSelectPosition) || 0;\r\n const endPos = parseInt(spot.endSelectPosition) || 0;\r\n\r\n if (startPos < 0 || endPos > text.length || startPos > endPos) {\r\n spotFixDebugLog('Invalid text positions: ' + spot);\r\n return;\r\n }\r\n\r\n markers.push({ position: startPos, type: 'start' });\r\n markers.push({ position: endPos, type: 'end' });\r\n });\r\n\r\n if (markers.length === 0) return;\r\n\r\n // Sort markers backward\r\n markers.sort((a, b) => b.position - a.position);\r\n\r\n // Check here that element (from meta.nodePath) contains same inner text as in meta.selectedText\r\n // Is the `text` in the element equal to the selected text `spotSelectedText`\r\n if ( text.slice(markers[1].position, markers[0].position) !== spotSelectedText ) {\r\n spotFixDebugLog('It is not allow to highlight element by provided metadata.');\r\n return;\r\n }\r\n\r\n let result = text;\r\n markers.forEach(marker => {\r\n const insertText = marker.type === 'start'\r\n ? spotfixHighlightOpen\r\n : spotfixHighlightClose;\r\n\r\n result = result.slice(0, marker.position) + insertText + result.slice(marker.position);\r\n });\r\n\r\n // Safety HTML insert\r\n try {\r\n element.innerHTML = ksesFilter(result);\r\n document.querySelectorAll('.doboard_task_widget-see-task').forEach(link => {\r\n link.addEventListener('click', (e) => {\r\n\r\n e.preventDefault();\r\n const classList = link.className.split(' ');\r\n const idClass = classList.find(cls => cls.includes('__task-id-'));\r\n let taskId = null;\r\n if (idClass) {\r\n taskId = idClass.split('__task-id-')[1];\r\n }\r\n if (taskId) {\r\n widgetInstance.currentActiveTaskId = taskId;\r\n widgetInstance.showOneTask();\r\n }\r\n });\r\n });\r\n } catch (error) {\r\n spotFixDebugLog('Error updating element content: ' + error);\r\n }\r\n}\r\n\r\n/**\r\n * Scroll to an element by tag, class, and text content\r\n * @param {array} path - The path to the element\r\n * @return {boolean} - True if the element was found and scrolled to, false otherwise\r\n */\r\nfunction spotFixScrollToNodePath(path) {\r\n const node = spotFixRetrieveNodeFromPath(path);\r\n if (node && node.scrollIntoView) {\r\n node.scrollIntoView({ behavior: 'smooth', block: 'center' });\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction spotFixRemoveHighlights() {\r\n const textSelectionclassName = 'doboard_task_widget-text_selection';\r\n const spans = document.querySelectorAll('.' + textSelectionclassName);\r\n const affectedParents = new Set(); // Track unique parents\r\n\r\n spans.forEach(span => {\r\n const parent = span.parentNode;\r\n affectedParents.add(parent); // Mark parent as affected\r\n const tooltip = span.querySelector('.doboard_task_widget-text_selection_tooltip');\r\n if (tooltip) tooltip.remove();\r\n\r\n // Move all child nodes out of the span and into the parent\r\n while (span.firstChild) {\r\n parent.insertBefore(span.firstChild, span);\r\n }\r\n parent.removeChild(span);\r\n });\r\n\r\n // Normalize all affected parents to merge adjacent text nodes\r\n affectedParents.forEach(parent => parent.normalize());\r\n\r\n const elementSelectionClassName = 'doboard_task_widget-element_selection';\r\n const elements = document.querySelectorAll(`.${elementSelectionClassName}`);\r\n elements.forEach(element => {\r\n element.classList.remove(elementSelectionClassName);\r\n });\r\n const imageSelectionClassName = 'doboard_task_widget-image_selection';\r\n const images = document.querySelectorAll(`.${imageSelectionClassName}`);\r\n images.forEach(element => {\r\n element.classList.remove(imageSelectionClassName);\r\n });\r\n}\r\n\r\n/**\r\n * Validate nodePath as array of indices\r\n * @param {Array} nodePath\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsValidNodePath(nodePath) {\r\n if (!Array.isArray(nodePath)) return false;\r\n if (nodePath.length === 0) return false;\r\n\r\n return nodePath.every(index => {\r\n return Number.isInteger(index) && index >= 0 && index < 1000;\r\n });\r\n}\r\n\r\n/**\r\n * Try to find selected image in selection.\r\n * @param selection\r\n * @returns {Node|*|null}\r\n */\r\nfunction spotFixGetSelectedImage(selection) {\r\n\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\r\n return null;\r\n }\r\n\r\n const range = selection.getRangeAt(0);\r\n\r\n // Is current end container IMG\r\n if (range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE &&\r\n range.startContainer.tagName === 'IMG') {\r\n return range.startContainer;\r\n }\r\n\r\n // Get img in the range\r\n const walker = document.createTreeWalker(\r\n range.commonAncestorContainer,\r\n NodeFilter.SHOW_ELEMENT,\r\n {\r\n acceptNode: function(node) {\r\n return node.tagName === 'IMG' &&\r\n spotFixIsElementInRange(node, range) ?\r\n NodeFilter.FILTER_ACCEPT :\r\n NodeFilter.FILTER_REJECT;\r\n }\r\n }\r\n );\r\n\r\n let imgNode = walker.nextNode();\r\n if (imgNode) {\r\n return imgNode;\r\n }\r\n\r\n // start/end containers\r\n const startElement = spotFixGetElementFromNode(range.startContainer);\r\n const endElement = spotFixGetElementFromNode(range.endContainer);\r\n\r\n // If selection starts on image\r\n if (startElement && startElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(startElement, range)) {\r\n return startElement;\r\n }\r\n\r\n if (endElement && endElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(endElement, range)) {\r\n return endElement;\r\n }\r\n\r\n // 4. Get closest IMG\r\n const nearbyElements = spotFixFindNearbyElements(range);\r\n for (const element of nearbyElements) {\r\n if (element.tagName === 'IMG') {\r\n return element;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction spotFixIsElementInRange(element, range) {\r\n const elementRange = document.createRange();\r\n elementRange.selectNode(element);\r\n return range.compareBoundaryPoints(Range.START_TO_START, elementRange) <= 0 &&\r\n range.compareBoundaryPoints(Range.END_TO_END, elementRange) >= 0;\r\n}\r\n\r\nfunction spotFixIsElementPartiallySelected(element, range) {\r\n const elementRect = element.getBoundingClientRect();\r\n const rangeRect = range.getBoundingClientRect();\r\n\r\n // bounding rectangles is crossed\r\n return !(elementRect.right < rangeRect.left ||\r\n elementRect.left > rangeRect.right ||\r\n elementRect.bottom < rangeRect.top ||\r\n elementRect.top > rangeRect.bottom);\r\n}\r\n\r\nfunction spotFixGetElementFromNode(node) {\r\n return node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n}\r\n\r\n/**\r\n * Find nearby elements in the range.\r\n * @param range\r\n * @returns {*[]}\r\n */\r\nfunction spotFixFindNearbyElements(range) {\r\n const elements = [];\r\n const container = range.commonAncestorContainer;\r\n\r\n // search elements\r\n const previousElement = container.previousElementSibling;\r\n const nextElement = container.nextElementSibling;\r\n\r\n if (previousElement) {\r\n elements.push(previousElement);\r\n }\r\n if (nextElement) {\r\n elements.push(nextElement);\r\n }\r\n\r\n // Also check child container\r\n if (container.nodeType === Node.ELEMENT_NODE) {\r\n const children = container.children;\r\n for (let i = 0; i < children.length; i++) {\r\n if (spotFixIsElementPartiallySelected(children[i], range)) {\r\n elements.push(children[i]);\r\n }\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Calculate the path of a DOM node\r\n *\r\n * @param {Node} node\r\n * @return {int[]}\r\n */\r\nfunction spotFixCalculateNodePath(node) {\r\n let path = [];\r\n while (node) {\r\n let index = 0;\r\n let sibling = node.previousSibling;\r\n while (sibling) {\r\n if (sibling.nodeType === 1) {\r\n index++;\r\n }\r\n sibling = sibling.previousSibling;\r\n }\r\n path.unshift(index);\r\n node = node.parentNode;\r\n }\r\n\r\n // Hard fix - need to remove first element to work correctly\r\n path.shift();\r\n\r\n return path;\r\n}\r\n\r\n/**\r\n * Retrieve a DOM node from a path\r\n *\r\n * @param {int[]} path\r\n * @return {*|null}\r\n */\r\nfunction spotFixRetrieveNodeFromPath(path) {\r\n // @ToDo check if the path is correct\r\n if ( ! path ) {\r\n return null;\r\n }\r\n\r\n let node = document;\r\n for (let i = 0; i < path.length; i++) {\r\n node = node.children[path[i]];\r\n if ( ! node ) {\r\n return null;\r\n }\r\n }\r\n return node;\r\n}\r\n\n/**\r\n * Return bool if widget is closed in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetWidgetIsClosed() {\r\n return localStorage.getItem('spotfix_widget_is_closed') === '1';\r\n}\r\n\r\n/**\r\n * Return bool if widget closed state is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageWidgetCloseIsSet() {\r\n return localStorage.getItem('spotfix_widget_is_closed') !== null;\r\n}\r\n\r\n/**\r\n * Save widget closed state\r\n * @param visible\r\n */\r\nfunction storageSetWidgetIsClosed(visible) {\r\n localStorage.setItem('spotfix_widget_is_closed', visible ? '1' : '0');\r\n}\r\n\r\n/**\r\n * Return bool if user is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetUserIsDefined() {\r\n return localStorage.getItem('spotfix_user_id') !== null;\r\n}\r\n\r\n/**\r\n * Save data for updates check\r\n * @param tasks\r\n */\r\nfunction storageSaveTasksUpdateData(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n\r\n tasks.forEach(task => {\r\n if (task.taskId && task.taskLastUpdate) {\r\n storedTasks[task.taskId] = {\r\n taskId: task.taskId,\r\n taskLastUpdate: task.taskLastUpdate\r\n };\r\n }\r\n });\r\n\r\n localStorage.setItem('spotfix_task_updates', JSON.stringify(storedTasks));\r\n}\r\n\r\nfunction storageSaveTasksCount(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n const count = tasks.filter(task => {\r\n return task.taskMeta;\r\n })?.length;\r\n\r\n localStorage.setItem('spotfix_tasks_count', `${count}`);\r\n}\r\n\r\n/**\r\n * Check if a specific task has been updated since last check\r\n * @param taskId\r\n * @param currentLastUpdate\r\n * @returns {boolean|null}\r\n */\r\nfunction storageCheckTaskUpdate(taskId, currentLastUpdate) {\r\n if (!taskId || !currentLastUpdate) {\r\n return null;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n const storedTask = storedTasks[taskId];\r\n\r\n if (!storedTask) {\r\n return false;\r\n }\r\n\r\n const storedUpdate = new Date(storedTask.taskLastUpdate);\r\n const currentUpdate = new Date(currentLastUpdate);\r\n return currentUpdate > storedUpdate;\r\n}\r\n\r\n/**\r\n * Add unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageAddUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n if (!storedUnread.includes(taskId)) {\r\n storedUnread.push(taskId);\r\n }\r\n\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Remove unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageRemoveUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n storedUnread = storedUnread.filter(id => id !== taskId);\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Check if there are any unread updates\r\n * @returns {boolean}\r\n */\r\nfunction storageTasksHasUnreadUpdates() {\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.length > 0;\r\n}\r\n\r\n/**\r\n * Check if a specific task has unread updates\r\n * @param taskId\r\n * @returns {boolean}\r\n */\r\nfunction storageProvidedTaskHasUnreadUpdates(taskId) {\r\n if (!taskId) {\r\n return false;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.includes(taskId.toString());\r\n}\r\n\r\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 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
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 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","reversed","u","domain","host","segments","pathname","split","Boolean","reverse","push","join","setToggleStatus","rootElement","toggle","checked","addEventListener","timer","setTimeout","hide","clearTimeout","checkLogInOutButtonsVisible","el","style","display","closest","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","spotFixCSS","SPOTFIX_SELECTION_TYPE_TEXT","SPOTFIX_SELECTION_TYPE_IMG","SPOTFIX_SELECTION_TYPE_ELEMENT","spotFixGetSelectionType","range","getRangeAt","commonAncestor","commonAncestorContainer","spotFixGetSelectedImage","startContainer","endContainer","hasTextContent","isTextNode","TEXT_NODE","isCollapsed","collapsed","rangeCount","selectionType","startSelectPosition","endSelectPosition","commonNode","commonNodeElement","startOffset","endOffset","spotFixCalculateNodePath","imgElement","selectedImage","from","children","indexOf","imageUrl","widgetInstance","elementsMap","Map","spot","spotFixIsValidNodePath","spotFixRetrieveNodeFromPath","has","set","spots","spotFixHighlightImageElement","spotFixHighlightNestedElement","spotFixHighlightTextInElement","tooltipTitleText","spotfixHighlightOpen","text","spotSelectedText","markers","startPos","parseInt","endPos","position","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","container","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","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/api.js b/js/src/api.js index 9381308..942c2cd 100644 --- a/js/src/api.js +++ b/js/src/api.js @@ -185,6 +185,23 @@ const loginUserDoboard = async (email, password) => { } } +const jogoutUserDoboard = async (accountId) => { + const sessionId = localStorage.getItem('spotfix_session_id'); + if(sessionId && accountId) { + const data = { + session_id: sessionId, + }; + + const result = await spotfixApiCall(data, 'user_unauthorize', accountId); + if(result.operation_status === 'SUCCESS') { + localStorage.removeItem('spotfix_email'); + localStorage.removeItem('spotfix_session_id'); + localStorage.removeItem('spotfix_user_id'); + localStorage.setItem('spotfix_widget_is_closed', '1'); + } + } +} + const getTasksDoboard = async (projectToken, sessionId, accountId, projectId, userId) => { const data = { session_id: sessionId, diff --git a/js/src/widget.js b/js/src/widget.js index 989e237..627c999 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -707,6 +707,10 @@ class CleanTalkWidgetDoboard { this.createWidgetElement('user_menu') }) || ''; + document.querySelector('#doboard_task_widget-user_menu-logout_button')?.addEventListener('click', () => { + jogoutUserDoboard(this.params.accountId); + }) || ''; + document.querySelector('#doboard_task_widget-user_menu-signlog_button')?.addEventListener('click', () => { spotFixShowWidget(); }) || ''; diff --git a/styles/doboard-widget.css b/styles/doboard-widget.css index 8c460ec..3288220 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -1132,9 +1132,14 @@ padding-bottom: 8px; } -.doboard_task_widget_tasks_list a { - color: #40484F !important; - text-decoration: none !important; +/*.doboard_task_widget_tasks_list a {*/ +/* color: #40484F !important;*/ +/* text-decoration: none !important;*/ +/*}*/ + +#doboard_task_widget-user_menu-logout_button { + display: inline-flex; + align-items: center; } .doboard_task_widget-text_selection { From 1e2d63f62b237e59fa398a6939037bbe7e4096cb Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Mon, 22 Dec 2025 20:35:27 +0400 Subject: [PATCH 07/20] Fix. Merge conflicts --- dist/doboard-widget-bundle.js | 2 +- dist/doboard-widget-bundle.min.js | 121 +++++++++++++++++++++++--- dist/doboard-widget-bundle.min.js.map | 2 +- 3 files changed, 113 insertions(+), 12 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index c3b361a..bfe77e3 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -2064,7 +2064,6 @@ function ksesFilter(html, options = false) { return doc.body.innerHTML; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`; /** * SELECTION will be grouped into three types: * 1 - Simple text within a single tag @@ -2802,6 +2801,7 @@ function storageProvidedTaskHasUnreadUpdates(taskId) { } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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}`; /** * File uploader handler for managing file attachments with validation and upload capabilities */ diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 7c2a5bf..e946210 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a)=>{e={session_id:e,project_token:t};return(await spotfixApiCall(e,"user_get",a)).users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}};async function confirmUserEmail(e,t){var e=await userConfirmEmailDoboard(e),a=(localStorage.setItem("spotfix_email",e.email),localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.getItem("spotfix_pending_task"));if(!a)throw new Error("No pending task data");let i;try{i=JSON.parse(a)}catch(e){throw new Error("Invalid pending task data")}a={taskTitle:i.selectedText||"New Task",taskDescription:i.description||"",selectedData:i,projectToken:t.projectToken,projectId:t.projectId,accountId:t.accountId,taskMeta:JSON.stringify(i)},t=await handleCreateTask(e.sessionId,a);return localStorage.removeItem("spotfix_pending_task"),t}async function getTasksFullDetails(e,t,a){var i;if(0+e.taskId==+a)?.taskStatus}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",l={...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,_=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);p=document.querySelector(".doboard_task_widget-issue-title");p&&(p.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;c=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(c&&c.taskMeta)try{i=JSON.parse(c.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var g=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),C){var D=C[S];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:T,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function E(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let a=this;e&&e.addEventListener("click",function(e,t=a){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",()=>{this.hide()}),document.querySelector("#doboard_task_widget-task_count")?.addEventListener("click",()=>{document.querySelector(".doboard_task_widget-wrap").classList.add("hidden"),storageSetWidgetIsClosed(!0)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e.taskId.toString()===t.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,u=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;i<_.length;i++){var m=_[i],h=m.taskId,w=m.taskTitle,b=m.taskMeta;let t=null;if(b)try{(t=JSON.parse(b)).isFixed="DONE"===m.taskStatus,t.taskId=m.taskId}catch(e){t=null}var k,x,b=t?t.pageURL:"",f=t?t.nodePath:"";let e="",a="Task publicity is unknown";t&&void 0!==t.isPublic&&(a=t.isPublic?(e=this.srcVariables.iconSpotPublic,"The task is public"):(e=this.srcVariables.iconSpotPrivate,"The task is private and visible only for registered DoBoard users")),b===window.location.href&&o++,r&&b!==window.location.href||(x=getAvatarData(k=getTaskFullDetails(n,h)),w={taskTitle:w||"",taskAuthorAvatarImgSrc:k.taskAuthorAvatarImgSrc,taskAuthorName:k.taskAuthorName,taskPublicStatusImgSrc:e,taskPublicStatusHint:a,taskLastMessage:ksesFilter(k.lastMessageText),taskPageUrl:b,iconLinkChain:this.srcVariables.iconLinkChain,taskFormattedPageUrl:spotFixSplitUrl(b),taskLastUpdate:k.lastMessageTime,nodePath:this.sanitizeNodePath(f),taskId:h,avatarCSSClass:x.avatarCSSClass,avatarStyle:x.avatarStyle,taskAuthorInitials:x.taskAuthorInitials,initialsClass:x.initialsClass,classUnread:"",elementBgCSSClass:"DONE"!==m.taskStatus?"":"doboard_task_widget-task_row-green",statusFixedHtml:"DONE"!==m.taskStatus?"":this.loadTemplate("fixedHtml")},storageProvidedTaskHasUnreadUpdates(k.taskId)&&(w.classUnread="unread"),document.querySelector(".doboard_task_widget-all_issues-container").innerHTML+=this.loadTemplate("list_issues",w),this.isSpotHaveToBeHighlighted(t)&&u.push(t))}this.savedIssuesQuantityOnPage=o,this.savedIssuesQuantityAll=g.length,spotFixHighlightElements(u,this),document.querySelector(".doboard_task_widget-header span").innerHTML+=ksesFilter(" "+getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll))}0===g.length&&(document.querySelector(".doboard_task_widget-all_issues-container").innerHTML=ksesFilter('
The issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name||"Guest",l.email=p.email||"",p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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-container{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_tasks_list a{color:#40484F!important;text-decoration:none!important}.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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0img{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-container{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}`;class FileUploader{constructor(e){this.files=[],this.maxFileSize=5242880,this.maxTotalSize=26214400,this.maxFiles=5,this.allowedTypes=["image/jpeg","image/png","image/gif","application/pdf","text/plain","application/msword"],this.escapeHtmlHandler=e,this.SIZE_UNITS=["Bytes","KB","MB","GB"]}init(){this.initializeElements(),this.bindFilesInputChange()}initializeElements(){this.fileInput=document.getElementById("doboard_task_widget__file-upload__file-input-button"),this.fileList=document.getElementById("doboard_task_widget__file-upload__file-list"),this.uploaderWrapper=document.getElementById("doboard_task_widget__file-upload__wrapper"),this.errorMessage=document.getElementById("doboard_task_widget__file-upload__error"),this.fileInput&&this.fileList&&this.errorMessage&&!this.uploaderWrapper||console.warn("File uploader elements not found")}bindFilesInputChange(){this.fileInput&&this.fileInput.addEventListener("change",e=>this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
@@ -19,7 +19,12 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) All spots
- +
+ + + + +
@@ -29,7 +34,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
@@ -41,7 +46,12 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) All {{issuesCounter}}
{{issueTitle}}
- +
+ + + + +
@@ -98,14 +108,19 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) Report an issue
- +
+ + + + +
- If you found issue with {{currentDomain}} page, you are in right place. Please use this form to tell us about the issue you’re experiencing. - doboard.com + Tell us about any issue you’re experiencing on {{currentDomain}}. + You’re also welcome to review spelling, grammar, or ask a question related to this page.
@@ -181,7 +196,63 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
-`}static wrap(){return` +`}static user_menu(){return` +
+
+
+
+ + Back +
+
+ +
+
+
+ + {{userName}} + {{email}} + + Sign up or Log in + +
+
+
+
+
+
+ +
+ + + Show widget on my screen + + The widget will be visible again if you select any text on the site + + +
+
+
+ + + Log out + +
+
+
+
+ {{spotfixVersion}} + Powered by + + doBoard + +
+
+
`}static wrap(){return`
@@ -193,10 +264,17 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) `}static fixedHtml(){return'

Finished

'}static fixedTaskHtml(){return'

This issue already fixed

'}}class SpotFixSVGLoader{static loadSVG(e){var t=this[e];if("function"!=typeof t)throw new Error(`Template method '${e}' not found`);return t.call(this).trim()}static getAsRawSVG(e){return this.loadSVG(e)}static getAsDataURI(e){e=this.loadSVG(e);return this.svgToDataURI(e)}static svgToDataURI(e){e=(new TextEncoder).encode(e);return"data:image/svg+xml;base64,"+btoa(String.fromCharCode(...e))}static chevronBack(){return` +`}static chevronBackDark(){return` + + `}static buttonCloseScreen(){return` +`}static buttonCloseScreenDark(){return` + + + `}static buttonSendMessage(){return` @@ -233,5 +311,28 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) `}static iconLinkChain(){return` -`}}class SpotFixSourcesLoader{constructor(){this.loadAll()}getCSSCode(){return spotFixCSS}loadAll(){this.loadFonts(),this.loadCSS()}loadFonts(){var e=document.createElement("link"),e=(e.rel="preconnect",e.href="https://fonts.googleapis.com",document.head.appendChild(e),document.createElement("link")),e=(e.rel="preconnect",e.href="https://fonts.gstatic.com",e.crossOrigin="crossorigin",document.head.appendChild(e),document.createElement("link"));e.rel="stylesheet",e.href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",document.head.appendChild(e)}loadCSS(){var e=document.createElement("style");e.setAttribute("id","spotfix_css"),e.textContent=this.getCSSCode(),document.head.appendChild(e)}}document.dispatchEvent(new CustomEvent("spotFixLoaded",{detail:{timestamp:(new Date).toISOString(),message:"All scripts loaded successfully"}})); +`}static iconEllipsesMore(){return` + + + +`}static iconAvatar(){return` + + + + + + + + +`}static iconEye(){return` + + + +`}static iconDoor(){return` + + + +`}}class SpotFixSourcesLoader{constructor(){this.loadAll()}getCSSCode(){return spotFixCSS}loadAll(){this.loadFonts(),this.loadCSS()}loadFonts(){var e=document.createElement("link"),e=(e.rel="preconnect",e.href="https://fonts.googleapis.com",document.head.appendChild(e),document.createElement("link")),e=(e.rel="preconnect",e.href="https://fonts.gstatic.com",e.crossOrigin="crossorigin",document.head.appendChild(e),document.createElement("link"));e.rel="stylesheet",e.href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",document.head.appendChild(e)}loadCSS(){var e=document.createElement("style");e.setAttribute("id","spotfix_css"),e.textContent=this.getCSSCode(),document.head.appendChild(e)}}document.dispatchEvent(new CustomEvent("spotFixLoaded",{detail:{timestamp:(new Date).toISOString(),message:"All scripts loaded successfully"}})); //# sourceMappingURL=doboard-widget-bundle.min.js.map diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 2d6a882..5b4ef1a 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';\n\n/**\n * Makes an API call to the DoBoard endpoint with form data\n *\n * @param {Object} data - The data to send in the request\n * @param {string} method - The API method to call\n * @param {string|number} accountId - Optional account ID for the endpoint\n *\n * @returns {Promise} The response data when operation_status is 'SUCCESS'\n */\nconst spotfixApiCall = async(data, method, accountId = undefined) => {\n if (!data || typeof data !== 'object') {\n throw new Error('Data must be a valid object');\n }\n\n if (!method || typeof method !== 'string') {\n throw new Error('Method must be a valid string');\n }\n\n if (accountId !== undefined && (typeof accountId !== 'string' && typeof accountId !== 'number')) {\n throw new Error('AccountId must be a string or number');\n }\n\n const formData = new FormData();\n for (const key in data) {\n if (data.hasOwnProperty(key)) {\n if (data[key] !== undefined && data[key] !== null) {\n formData.append(key, data[key]);\n }\n }\n }\n\n let endpointUrl;\n if (accountId !== undefined) {\n endpointUrl = `${DOBOARD_API_URL}/${accountId}/${method}`;\n } else {\n endpointUrl = `${DOBOARD_API_URL}/${method}`;\n }\n\n try {\n new URL(endpointUrl);\n } catch (error) {\n throw new Error(`Invalid endpoint URL: ${endpointUrl}`);\n }\n\n let response;\n try {\n response = await fetch(endpointUrl, {\n method: 'POST',\n body: formData,\n });\n } catch (networkError) {\n throw new Error(`Network error: ${networkError.message}`);\n }\n\n let responseBody;\n try {\n responseBody = await response.json();\n } catch (parseError) {\n throw new Error('Failed to parse JSON response from server');\n }\n\n if (!responseBody || typeof responseBody !== 'object') {\n throw new Error('Invalid response format from server');\n }\n\n if (!responseBody.data) {\n throw new Error('Missing data field in server response');\n }\n\n if (!responseBody.data.operation_status) {\n throw new Error('Missing operation_status in response data');\n }\n\n if (responseBody.data.operation_status === 'FAILED') {\n const errorMessage = responseBody.data.operation_message || 'Operation failed without specific message';\n throw new Error(errorMessage);\n }\n\n if (responseBody.data.operation_status === 'SUCCESS') {\n return responseBody.data;\n }\n\n throw new Error(`Unknown operation status: ${responseBody.data.operation_status}`);\n}\n\nconst userConfirmEmailDoboard = async (emailConfirmationToken) => {\n const data = {\n email_confirmation_token: encodeURIComponent(emailConfirmationToken)\n }\n const result = await spotfixApiCall(data, 'user_confirm_email');\n return {\n sessionId: result.session_id,\n userId: result.user_id,\n email: result.email,\n accounts: result.accounts,\n operationStatus: result.operation_status\n };\n};\n\nconst createTaskDoboard = async (sessionId, taskDetails) => {\n const accountId = taskDetails.accountId\n const data = {\n session_id: sessionId,\n project_token: taskDetails.projectToken,\n project_id: taskDetails.projectId,\n user_id: localStorage.getItem('spotfix_user_id'),\n name: taskDetails.taskTitle,\n comment: taskDetails.taskDescription,\n meta: taskDetails.taskMeta,\n task_type: 'PUBLIC'\n }\n const result = await spotfixApiCall(data, 'task_add', accountId);\n return {\n taskId: result.task_id,\n }\n};\n\nconst createTaskCommentDoboard = async (accountId, sessionId, taskId, comment, projectToken, status = 'ACTIVE') => {\n const data = {\n session_id: sessionId,\n project_token: projectToken,\n task_id: taskId,\n comment: comment,\n status: status\n }\n const result = await spotfixApiCall(data, 'comment_add', accountId);\n return {\n commentId: result.comment_id,\n };\n};\n\nconst attachmentAddDoboard = async (fileData) => {\n const accountId = fileData.params.accountId;\n const data = {\n session_id: fileData.sessionId,\n project_token: fileData.params.projectToken,\n account_id: fileData.params.accountId,\n comment_id: fileData.commentId,\n filename: fileData.fileName,\n file: fileData.fileBinary,\n attachment_order: fileData.attachmentOrder\n }\n const result = await spotfixApiCall(data, 'attachment_add', accountId);\n // @ToDo need to handle result?\n};\n\nconst registerUserDoboard = async (projectToken, accountId, email, nickname, pageURL) => {\n let data = {\n project_token: projectToken,\n account_id: accountId,\n confirmation_url: email,\n }\n if (email && nickname) {\n data.email = email;\n data.name = nickname;\n }\n const result = await spotfixApiCall(data, 'user_registration');\n return {\n sessionId: result.session_id,\n userId: result.user_id,\n email: result.email,\n accountExists: result.user_email_confirmed === 1,\n operationMessage: result.operation_message,\n operationStatus: result.operation_status,\n userEmailConfirmed: result.user_email_confirmed,\n };\n};\n\nconst loginUserDoboard = async (email, password) => {\n const data = {\n email: email,\n password: password,\n }\n const result = await spotfixApiCall(data, 'user_authorize');\n return {\n sessionId: result.session_id,\n userId: result.user_id,\n email: result.email,\n accountExists: result.user_email_confirmed === 1,\n operationMessage: result.operation_message,\n operationStatus: result.operation_status,\n userEmailConfirmed: result.user_email_confirmed,\n }\n}\n\nconst getTasksDoboard = async (projectToken, sessionId, accountId, projectId, userId) => {\n const data = {\n session_id: sessionId,\n project_token: projectToken,\n project_id: projectId,\n task_type: 'PUBLIC'\n }\n if ( userId ) {\n data.user_id = userId;\n }\n const result = await spotfixApiCall(data, 'task_get', accountId);\n const tasks = result.tasks.map(task => ({\n taskId: task.task_id,\n taskTitle: task.name,\n taskLastUpdate: task.updated,\n taskCreated: task.created,\n taskCreatorTaskUser: task.creator_user_id,\n taskMeta: task.meta,\n taskStatus: task.status,\n }));\n\n storageSaveTasksCount(tasks);\n\n return tasks;\n}\n\n\nconst getTasksCommentsDoboard = async (sessionId, accountId, projectToken, status = 'ACTIVE') => {\n const data = {\n session_id: sessionId,\n project_token: projectToken,\n status: status\n }\n const result = await spotfixApiCall(data, 'comment_get', accountId);\n return result.comments.map(comment => ({\n taskId: comment.task_id,\n commentId: comment.comment_id,\n userId: comment.user_id,\n commentBody: comment.comment,\n commentDate: comment.updated,\n status: comment.status,\n issueTitle: comment.task_name,\n }));\n};\n\nconst getUserDoboard = async (sessionId, projectToken, accountId) => {\n const data = {\n session_id: sessionId,\n project_token: projectToken,\n }\n const result = await spotfixApiCall(data, 'user_get', accountId);\n return result.users;\n\n // @ToDo Need to handle these two different answers?\n /*// Format 1: users inside data\n if (responseBody.data && responseBody.data.operation_status) {\n if (responseBody.data.operation_status === 'FAILED') {\n throw new Error(responseBody.data.operation_message);\n }\n if (responseBody.data.operation_status === 'SUCCESS') {\n if (Array.isArray(responseBody.data.users)) {\n return responseBody.data.users;\n }\n return [];\n }\n }\n // Format 2: users at the top level\n if (responseBody.operation_status) {\n if (responseBody.operation_status === 'FAILED') {\n throw new Error(responseBody.operation_message);\n }\n if (responseBody.operation_status === 'SUCCESS') {\n if (Array.isArray(responseBody.users)) {\n return responseBody.users;\n }\n return [];\n }\n }*/\n};\n\nconst userUpdateDoboard = async (projectToken, accountId, sessionId, userId, timezone) => {\n const data = {\n session_id: sessionId,\n project_token: projectToken,\n user_id: userId,\n timestamp: timezone\n }\n await spotfixApiCall(data, 'user_update', accountId);\n return {\n success: true\n };\n}\n\nasync function confirmUserEmail(emailConfirmationToken, params) {\n\tconst result = await userConfirmEmailDoboard(emailConfirmationToken);\n\t// Save session data to LS\n\tlocalStorage.setItem('spotfix_email', result.email);\n\tlocalStorage.setItem('spotfix_session_id', result.sessionId);\n\tlocalStorage.setItem('spotfix_user_id', result.userId);\n\n\t// Get pending task from LS\n\tconst pendingTaskRaw = localStorage.getItem('spotfix_pending_task');\n\tif (!pendingTaskRaw) throw new Error('No pending task data');\n\n\tlet pendingTask;\n\ttry {\n\t\tpendingTask = JSON.parse(pendingTaskRaw);\n\t} catch (error) {\n\t\tthrow new Error('Invalid pending task data');\n\t}\n\n\t// Form taskDetails for task creation\n\tconst taskDetails = {\n\t\ttaskTitle: pendingTask.selectedText || 'New Task',\n\t\ttaskDescription: pendingTask.description || '',\n\t\tselectedData: pendingTask,\n\t\tprojectToken: params.projectToken,\n\t\tprojectId: params.projectId,\n\t\taccountId: params.accountId,\n\t\ttaskMeta: JSON.stringify(pendingTask)\n\t};\n\n\t// Create task\n\tconst createdTask = await handleCreateTask(result.sessionId, taskDetails);\n\t// Clear pending task\n\tlocalStorage.removeItem('spotfix_pending_task');\n\n\t// Return created task\n\treturn createdTask;\n}\n\nasync function getTasksFullDetails(params, tasks, currentActiveTaskId) {\n if (tasks.length > 0) {\n const sessionId = localStorage.getItem('spotfix_session_id');\n const comments = await getTasksCommentsDoboard(sessionId, params.accountId, params.projectToken);\n const users = await getUserDoboard(sessionId, params.projectToken, params.accountId);\n\t\tconst foundTask = tasks.find(item => +item.taskId === +currentActiveTaskId);\n\n return {\n comments: comments,\n users: users,\n\t\t\ttaskStatus: foundTask?.taskStatus,\n };\n }\n}\n\nasync function handleCreateTask(sessionId, taskDetails) {\n\ttry {\n\t\tconst result = await createTaskDoboard(sessionId, taskDetails);\n\t\tif (result && result.taskId && taskDetails.taskDescription) {\n const sign = `


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

Finished

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

This issue already fixed

`;\n }\n\n}\n\nclass SpotFixSVGLoader {\n static loadSVG(svgName) {\n const svgMethod = this[svgName];\n\n if (typeof svgMethod !== 'function') {\n throw new Error(`Template method '${svgName}' not found`);\n }\n\n return svgMethod.call(this).trim();\n }\n\n static getAsRawSVG(svgName) {\n return this.loadSVG(svgName);\n }\n\n static getAsDataURI(svgName) {\n const svg = this.loadSVG(svgName);\n return this.svgToDataURI(svg);\n }\n\n static svgToDataURI(svgString) {\n const bytes = new TextEncoder().encode(svgString);\n const baseBtoa = btoa(String.fromCharCode(...bytes));\n return `data:image/svg+xml;base64,${baseBtoa}`;\n }\n\n static chevronBack() {\n return `\n\n \n`;\n }\n\n static buttonCloseScreen() {\n return `\n\n\n\n`;\n }\n\n static buttonSendMessage() {\n return `\n\n \n \n \n \n \n \n \n \n \n \n`;\n }\n\n static buttonPaperClip() {\n return `\n\n \n`;\n }\n\n static logoDoBoardWhite() {\n return `\n\n\n`;\n }\n\n static logoDoBoardWrap() {\n return `\n\n\n\n`;\n }\n\n static iconSpotPublic() {\n return `\n\n\n`;\n }\n\n static iconSpotPrivate() {\n return `\n\n\n\n\n`;\n }\n\n static iconSpotWidgetWrapPencil() {\n return `\n\n\n`;\n }\n\n static iconLinkChain() {\n return `\n\n\n`;\n }\n}\n\nclass SpotFixSourcesLoader {\n\n constructor() {\n this.loadAll();\n }\n\n getCSSCode() {\n // global gulp wrapper var\n return spotFixCSS;\n }\n\n loadAll() {\n this.loadFonts();\n this.loadCSS();\n };\n\n loadFonts() {\n const preconnect_first = document.createElement('link');\n preconnect_first.rel = 'preconnect';\n preconnect_first.href = 'https://fonts.googleapis.com';\n document.head.appendChild(preconnect_first);\n\n const preconnect_second = document.createElement('link');\n preconnect_second.rel = 'preconnect';\n preconnect_second.href = 'https://fonts.gstatic.com';\n preconnect_second.crossOrigin = 'crossorigin';\n document.head.appendChild(preconnect_second);\n\n const fontLink = document.createElement('link');\n fontLink.rel = 'stylesheet';\n fontLink.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap';\n document.head.appendChild(fontLink);\n }\n\n loadCSS() {\n const style = document.createElement('style');\n style.setAttribute('id', 'spotfix_css');\n style.textContent = this.getCSSCode();\n document.head.appendChild(style);\n }\n}\n\ndocument.dispatchEvent(new CustomEvent('spotFixLoaded', {\n detail: {\n timestamp: new Date().toISOString(),\n message: 'All scripts loaded successfully'\n }\n}));\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","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","confirmUserEmail","pendingTaskRaw","setItem","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","removeItem","getTasksFullDetails","currentActiveTaskId","length","find","item","sign","window","location","href","addTaskComment","err","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","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","addEventListener","taskTitleElement","value","taskDescriptionElement","loginSectionElement","contains","userEmailElement","userNameElement","userPasswordElement","style","borderColor","disabled","submitTaskResult","submitTask","cursor","needToLogin","isPublic","hideContainersSpinner","showOnlyCurrentPage","widgetContainer","createElement","className","innerHTML","removeAttribute","templateName","tasksFullDetails","templateVariables","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issueTitleElement","currentTaskData","String","issuesCommentsContainer","dayMessagesData","initIssuerID","storageRemoveUnreadUpdateForTaskID","userIsIssuer","Number","commentUserId","commentAuthorAvatarSrc","commentAuthorName","commentData","commentTime","issueMessageClassOwner","daysWrapperHTML","day","messageId","currentDayMessages","dayMessagesWrapperHTML","localeCompare","currentMessageTemplateVariables","dayContentMonthDay","dayContentMessages","textarea","handleTextareaChange","setTimeout","contentContainer","scrollTo","top","scrollHeight","behavior","sendButton","widgetClass","preventDefault","input","closest","newCommentResponse","alert","hasFiles","attachmentsSendResult","sendAttachmentsForComment","showError","toConsole","console","log","backToAllIssuesController","self","paperclipController","bindPaperClipAction","hide","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","toggle","handleScroll","bind","handleResize","messageText","titleSpan","messageDiv","messageWrap","color","widget","widgetCreateIssue","widgetConcreteIssue","scrollY","viewportHeight","innerHeight","selectionAbsoluteTop","getBoundingClientRect","widgetHeight","offsetHeight","bottom","clearTimeout","scrollTimeout","resizeTimeout","str","spotFixShowDelayTimeout","SPOTFIX_DEBUG","SPOTFIX_SHOW_DELAY","spotFixInit","SpotFixSourcesLoader","spotFixShowWidget","spotFixIsInsideWidget","node","el","nodeType","Node","ELEMENT_NODE","parentElement","spotFixDebugLog","spinners","getElementsByClassName","display","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","s","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","position","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","container","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","wrap","wrap_review","fixedHtml","fixedTaskHtml","loadSVG","svgName","svgMethod","getAsRawSVG","svg","svgToDataURI","svgString","TextEncoder","encode","btoa","fromCharCode","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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 || '';\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\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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 jogoutUserDoboard(this.params.accountId);\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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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\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\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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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 * 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 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
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 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","position","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","container","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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 From fc88c415128b0ddc336007b8fdcd3cf7b6f2def5 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Tue, 23 Dec 2025 01:39:07 +0400 Subject: [PATCH 08/20] Upd. Added the ability to change the size, added new icons and adjusted them for the mobile version, added full links to tasks, added the ability to create tasks without linking to elements --- dist/doboard-widget-bundle.js | 102 ++++++++++++++++++++--- dist/doboard-widget-bundle.min.js | 38 +++++++-- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/api.js | 2 +- js/src/loaders/SpotFixSVGLoader.js | 18 ++++ js/src/loaders/SpotFixTemplatesLoader.js | 24 +++++- js/src/widget.js | 56 +++++++++++-- styles/doboard-widget.css | 30 ++++++- 8 files changed, 242 insertions(+), 30 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index bfe77e3..0ea5802 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -100,7 +100,7 @@ const userConfirmEmailDoboard = async (emailConfirmationToken) => { }; const createTaskDoboard = async (sessionId, taskDetails) => { - const accountId = taskDetails.accountId + const accountId = taskDetails.accountId; const data = { session_id: sessionId, project_token: taskDetails.projectToken, @@ -642,8 +642,11 @@ class CleanTalkWidgetDoboard { this.selectedText = selectedData?.selectedText || ''; this.init(type); this.srcVariables = { + widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), + iconPlus: SpotFixSVGLoader.getAsDataURI('iconPlus'), + iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'), chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'), buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'), buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'), @@ -831,8 +834,9 @@ class CleanTalkWidgetDoboard { projectToken: this.params.projectToken, projectId: this.params.projectId, accountId: this.params.accountId, - taskMeta: JSON.stringify(this.selectedData), + taskMeta: JSON.stringify(this.selectedData ? this.selectedData : {pageURL:"http://localhost/"}), }; + if ( userEmail ) { taskDetails.userEmail = userEmail } @@ -904,8 +908,10 @@ class CleanTalkWidgetDoboard { this.type_name = templateName; templateVariables = { selectedText: this.selectedText, + widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', currentDomain: document.location.hostname || '', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), + iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'), iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), ...this.srcVariables }; @@ -925,7 +931,9 @@ class CleanTalkWidgetDoboard { case 'all_issues': templateName = 'all_issues'; this.type_name = templateName; - templateVariables = {...this.srcVariables}; + templateVariables = { + widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', + ...this.srcVariables}; break; case 'user_menu': templateName = 'user_menu'; @@ -959,6 +967,7 @@ class CleanTalkWidgetDoboard { templateVariables = { issueTitle: '...', issueComments: [], + widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', issuesCounter: getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll), ...this.srcVariables, }; @@ -978,6 +987,7 @@ class CleanTalkWidgetDoboard { const selection = window.getSelection(); const sessionIdExists = !!localStorage.getItem('spotfix_session_id'); const email = localStorage.getItem('spotfix_email'); + if (sessionIdExists && email && !email.includes('spotfix_')) { document.querySelector('.doboard_task_widget-login').classList.add('hidden'); } @@ -1007,7 +1017,15 @@ class CleanTalkWidgetDoboard { }); break; case 'all_issues': - spotFixRemoveHighlights(); + const container = document.querySelector('.doboard_task_widget-container'); + + if(+localStorage.getItem('maximize')){ + container.classList.add('doboard_task_widget-container-maximize'); + } else { + container.classList.remove('doboard_task_widget-container-maximize'); + } + + spotFixRemoveHighlights(); let issuesQuantityOnPage = 0; if (!this.allTasksData?.length) { this.allTasksData = await getAllTasks(this.params); @@ -1140,10 +1158,8 @@ class CleanTalkWidgetDoboard { break; case 'concrete_issue': - tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId); const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId); - // Update issue title in the interface const issueTitleElement = document.querySelector('.doboard_task_widget-issue-title'); if (issueTitleElement) { @@ -1153,21 +1169,30 @@ class CleanTalkWidgetDoboard { templateVariables.issueTitle = taskDetails?.issueTitle; templateVariables.issueComments = taskDetails?.issueComments; - widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables); - document.body.appendChild(widgetContainer); // Highlight the task's selected text let nodePath = null; const currentTaskData = this.allTasksData.find((element) => String(element.taskId) === String(taskDetails.taskId)); let meta = null; + if (currentTaskData && currentTaskData.taskMeta) { try { meta = JSON.parse(currentTaskData.taskMeta); nodePath = meta.nodePath || null; } catch (e) { nodePath = null; meta = null; } } + + templateVariables.taskPageUrl = meta.pageURL; + const taskFormattedPageUrl = meta.pageURL.replace(window.location.origin, ''); + templateVariables.taskFormattedPageUrl = taskFormattedPageUrl.length < 2 + ? meta.pageURL.replace(window.location.protocol + '/', '') : taskFormattedPageUrl; + + widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables); + document.body.appendChild(widgetContainer); + // remove old highlights before adding new ones spotFixRemoveHighlights(); + if (meta && nodePath) { // Pass the task meta object as an array spotFixHighlightElements([meta], this); @@ -1333,6 +1358,22 @@ class CleanTalkWidgetDoboard { jogoutUserDoboard(this.params.accountId); }) || ''; + document.getElementById('addNewTaskButton')?.addEventListener('click', () => { + spotFixShowWidget(); + }) || ''; + + document.getElementById('maximizeWidgetContainer')?.addEventListener('click', () => { + const container = document.querySelector('.doboard_task_widget-container'); + + if(+localStorage.getItem('maximize') && container.classList.contains('doboard_task_widget-container-maximize')){ + localStorage.setItem('maximize', '0'); + container.classList.remove('doboard_task_widget-container-maximize'); + } else { + localStorage.setItem('maximize', '1'); + container.classList.add('doboard_task_widget-container-maximize'); + } + }) || ''; + document.querySelector('#doboard_task_widget-user_menu-signlog_button')?.addEventListener('click', () => { spotFixShowWidget(); }) || ''; @@ -1512,6 +1553,7 @@ class CleanTalkWidgetDoboard { hide() { spotFixRemoveHighlights(); this.createWidgetElement('wrap'); + } wrapElementWithSpotfixHighlight(element) { @@ -2623,6 +2665,7 @@ function spotFixRetrieveNodeFromPath(path) { return node; } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} @@ -2801,7 +2844,6 @@ function storageProvidedTaskHasUnreadUpdates(taskId) { } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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}`; /** * File uploader handler for managing file attachments with validation and upload capabilities */ @@ -3209,16 +3251,22 @@ class SpotFixTemplatesLoader { static all_issues() { return ` -
+
All spots
+ + + + + +
@@ -3239,7 +3287,7 @@ class SpotFixTemplatesLoader { static concrete_issue() { return ` -
+
@@ -3247,13 +3295,22 @@ class SpotFixTemplatesLoader {
{{issueTitle}}
+ + + + + +
+
@@ -3314,7 +3371,7 @@ class SpotFixTemplatesLoader { static create_issue() { return ` -
+
@@ -3324,6 +3381,9 @@ class SpotFixTemplatesLoader { + + +
@@ -3661,6 +3721,24 @@ class SpotFixSVGLoader { +`; + } + + static iconPlus() { + return ` + + + +`; + } + + static iconMaximize() { + return ` + + + + + `; } } diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index e946210..6d6cf5f 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData)});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var g=this.allTasksData,u=(n=await getTasksFullDetails(this.params,g,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;i<_.length;i++){var m=_[i],h=m.taskId,w=m.taskTitle,b=m.taskMeta;let t=null;if(b)try{(t=JSON.parse(b)).isFixed="DONE"===m.taskStatus,t.taskId=m.taskId}catch(e){t=null}var k,x,b=t?t.pageURL:"",f=t?t.nodePath:"";let e="",a="Task publicity is unknown";t&&void 0!==t.isPublic&&(a=t.isPublic?(e=this.srcVariables.iconSpotPublic,"The task is public"):(e=this.srcVariables.iconSpotPrivate,"The task is private and visible only for registered DoBoard users")),b===window.location.href&&o++,r&&b!==window.location.href||(x=getAvatarData(k=getTaskFullDetails(n,h)),w={taskTitle:w||"",taskAuthorAvatarImgSrc:k.taskAuthorAvatarImgSrc,taskAuthorName:k.taskAuthorName,taskPublicStatusImgSrc:e,taskPublicStatusHint:a,taskLastMessage:ksesFilter(k.lastMessageText),taskPageUrl:b,iconLinkChain:this.srcVariables.iconLinkChain,taskFormattedPageUrl:spotFixSplitUrl(b),taskLastUpdate:k.lastMessageTime,nodePath:this.sanitizeNodePath(f),taskId:h,avatarCSSClass:x.avatarCSSClass,avatarStyle:x.avatarStyle,taskAuthorInitials:x.taskAuthorInitials,initialsClass:x.initialsClass,classUnread:"",elementBgCSSClass:"DONE"!==m.taskStatus?"":"doboard_task_widget-task_row-green",statusFixedHtml:"DONE"!==m.taskStatus?"":this.loadTemplate("fixedHtml")},storageProvidedTaskHasUnreadUpdates(k.taskId)&&(w.classUnread="unread"),document.querySelector(".doboard_task_widget-all_issues-container").innerHTML+=this.loadTemplate("list_issues",w),this.isSpotHaveToBeHighlighted(t)&&u.push(t))}this.savedIssuesQuantityOnPage=o,this.savedIssuesQuantityAll=g.length,spotFixHighlightElements(u,this),document.querySelector(".doboard_task_widget-header span").innerHTML+=ksesFilter(" "+getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll))}0===g.length&&(document.querySelector(".doboard_task_widget-all_issues-container").innerHTML=ksesFilter('
The issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();p=await getUserDetails(this.params),c=await getReleaseVersion(),g=localStorage.getItem("spotfix_app_version")||c;l.spotfixVersion=(g?`Spotfix version ${g}.`:"")||"",p&&(l.userName=p.name||"Guest",l.email=p.email||"",p?.avatar?.s)&&(l.avatar=p?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);c=document.querySelector(".doboard_task_widget-issue-title");c&&(c.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d);let t=null;g=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(g&&g.taskMeta)try{i=JSON.parse(g.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t);var p=document.querySelector(".doboard_task_widget-concrete_issues-container"),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),S){var E=S[C];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}p.innerHTML=t}else p.innerHTML=ksesFilter("No comments");c=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={widgetContainerClases:+localStorage.getItem("maximize")?"doboard_task_widget-container doboard_task_widget-container-maximize":"doboard_task_widget-container",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,widgetContainerClases:+localStorage.getItem("maximize")?"doboard_task_widget-container doboard_task_widget-container-maximize":"doboard_task_widget-container",currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={widgetContainerClases:+localStorage.getItem("maximize")?"doboard_task_widget-container doboard_task_widget-container-maximize":"doboard_task_widget-container",...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],widgetContainerClases:+localStorage.getItem("maximize")?"doboard_task_widget-container doboard_task_widget-container-maximize":"doboard_task_widget-container",issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":g=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")?g.classList.add("doboard_task_widget-container-maximize"):g.classList.remove("doboard_task_widget-container-maximize"),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();c=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",c&&(l.userName=c.name||"Guest",l.email=c.email||"",c?.avatar?.s)&&(l.avatar=c?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var c=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=c.length<2?i.pageURL.replace(window.location.protocol+"/",""):c,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),T){var E=T[S];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0img{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-container{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}`;class FileUploader{constructor(e){this.files=[],this.maxFileSize=5242880,this.maxTotalSize=26214400,this.maxFiles=5,this.allowedTypes=["image/jpeg","image/png","image/gif","application/pdf","text/plain","application/msword"],this.escapeHtmlHandler=e,this.SIZE_UNITS=["Bytes","KB","MB","GB"]}init(){this.initializeElements(),this.bindFilesInputChange()}initializeElements(){this.fileInput=document.getElementById("doboard_task_widget__file-upload__file-input-button"),this.fileList=document.getElementById("doboard_task_widget__file-upload__file-list"),this.uploaderWrapper=document.getElementById("doboard_task_widget__file-upload__wrapper"),this.errorMessage=document.getElementById("doboard_task_widget__file-upload__error"),this.fileInput&&this.fileList&&this.errorMessage&&!this.uploaderWrapper||console.warn("File uploader elements not found")}bindFilesInputChange(){this.fileInput&&this.fileInput.addEventListener("change",e=>this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
@@ -13,16 +13,22 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
`),e.querySelector(".doboard_task_widget__file-upload__remove-btn").addEventListener("click",()=>this.removeFile(a)),e}formatFileSize(e){var t;return 0===e?"0 Bytes":(t=Math.floor(Math.log(e)/Math.log(1024)),parseFloat((e/Math.pow(1024,t)).toFixed(2))+" "+this.SIZE_UNITS[t])}showError(e){this.errorMessage&&(this.errorMessage.textContent=e,this.errorMessage.style.display="block")}clearError(){this.errorMessage&&(this.errorMessage.textContent="",this.errorMessage.style.display="none")}hasFiles(){return 0e?.[t],e)}async sendSingleAttachment(e){e=await this.validateFileData(e);return attachmentAddDoboard(e)}async sendAttachmentsForComment(t,a,i){var o={preparedFilesCount:this.files.length,sentFilesCount:0,fileResults:[],success:!0};for(let e=0;e +
All spots
+ + + + + +
@@ -39,7 +45,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
`}static concrete_issue(){return` -
+
@@ -47,13 +53,22 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
{{issueTitle}}
+ + + + + +
+
@@ -102,7 +117,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
`}static create_issue(){return` -
+
@@ -112,6 +127,9 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) + + +
@@ -334,5 +352,15 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) +`}static iconPlus(){return` + + + +`}static iconMaximize(){return` + + + + + `}}class SpotFixSourcesLoader{constructor(){this.loadAll()}getCSSCode(){return spotFixCSS}loadAll(){this.loadFonts(),this.loadCSS()}loadFonts(){var e=document.createElement("link"),e=(e.rel="preconnect",e.href="https://fonts.googleapis.com",document.head.appendChild(e),document.createElement("link")),e=(e.rel="preconnect",e.href="https://fonts.gstatic.com",e.crossOrigin="crossorigin",document.head.appendChild(e),document.createElement("link"));e.rel="stylesheet",e.href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",document.head.appendChild(e)}loadCSS(){var e=document.createElement("style");e.setAttribute("id","spotfix_css"),e.textContent=this.getCSSCode(),document.head.appendChild(e)}}document.dispatchEvent(new CustomEvent("spotFixLoaded",{detail:{timestamp:(new Date).toISOString(),message:"All scripts loaded successfully"}})); //# sourceMappingURL=doboard-widget-bundle.min.js.map diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 5b4ef1a..5a3f2fb 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'),\r\n buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'),\r\n buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'),\r\n logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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),\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 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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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\r\n switch (type) {\r\n case 'create_issue':\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 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 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 || '';\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\r\n tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId);\r\n const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId);\r\n\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 widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables);\r\n document.body.appendChild(widgetContainer);\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 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 // remove old highlights before adding new ones\r\n spotFixRemoveHighlights();\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 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 jogoutUserDoboard(this.params.accountId);\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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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 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\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\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:#FFF;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{width:400px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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%;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-container{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 * 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 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
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 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","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","issuesCommentsContainer","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","position","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","container","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container',\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 logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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:\"http://localhost/\"}),\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 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 widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container',\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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'all_issues':\r\n templateName = 'all_issues';\r\n this.type_name = templateName;\r\n templateVariables = {\r\n widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container',\r\n ...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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 widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container',\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\r\n switch (type) {\r\n case 'create_issue':\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 const container = document.querySelector('.doboard_task_widget-container');\r\n\r\n if(+localStorage.getItem('maximize')){\r\n container.classList.add('doboard_task_widget-container-maximize');\r\n } else {\r\n container.classList.remove('doboard_task_widget-container-maximize');\r\n }\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 || '';\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 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\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 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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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:#FFF;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:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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\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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","widgetContainerClases","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","iconPlus","iconMaximize","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","spotFixScrollToNodePath","spotFixGetSelectedData","nodePath","positionWidgetContainer","getTaskCount","widgetElementClasses","currentTarget","spotFixOpenWidget","container","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","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","position","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":"AAAA,IAAMA,gBAAkB,0BAWlBC,eAAiBC,MAAMC,EAAMC,EAAQC,EAAYC,KAAAA,KACnD,GAAI,CAACH,GAAwB,UAAhB,OAAOA,EAChB,MAAM,IAAII,MAAM,6BAA6B,EAGjD,GAAI,CAACH,GAA4B,UAAlB,OAAOA,EAClB,MAAM,IAAIG,MAAM,+BAA+B,EAGnD,GAAkBD,KAAAA,IAAdD,GAAiD,UAArB,OAAOA,GAA+C,UAArB,OAAOA,EACpE,MAAM,IAAIE,MAAM,sCAAsC,EAG1D,IACWC,EADLC,EAAW,IAAIC,SACrB,IAAWF,KAAOL,EACVA,EAAKQ,eAAeH,CAAG,GACnBL,MAAAA,EAAKK,IACLC,EAASG,OAAOJ,EAAKL,EAAKK,EAAI,EAK1CK,IAAIC,EAEAA,EADcR,KAAAA,IAAdD,EACiBL,oBAAmBK,KAAaD,EAEhCJ,gBAAH,IAAsBI,EAGxC,IACI,IAAIW,IAAID,CAAW,CAGvB,CAFE,MAAOE,GACL,MAAM,IAAIT,MAAM,yBAAyBO,CAAa,CAC1D,CAEAD,IAAII,EACJ,IACIA,EAAWC,MAAMC,MAAML,EAAa,CAChCV,OAAQ,OACRgB,KAAMX,CACV,CAAC,CAGL,CAFE,MAAOY,GACL,MAAM,IAAId,MAAM,kBAAkBc,EAAaC,OAAS,CAC5D,CAEAT,IAAIU,EACJ,IACIA,EAAeL,MAAMD,EAASO,KAAK,CAGvC,CAFE,MAAOC,GACL,MAAM,IAAIlB,MAAM,2CAA2C,CAC/D,CAEA,GAAI,CAACgB,GAAwC,UAAxB,OAAOA,EACxB,MAAM,IAAIhB,MAAM,qCAAqC,EAGzD,GAAI,CAACgB,EAAapB,KACd,MAAM,IAAII,MAAM,uCAAuC,EAG3D,GAAI,CAACgB,EAAapB,KAAKuB,iBACnB,MAAM,IAAInB,MAAM,2CAA2C,EAG/D,GAA2C,WAAvCgB,EAAapB,KAAKuB,iBAElB,MADMC,EAAeJ,EAAapB,KAAKyB,mBAAqB,4CACtD,IAAIrB,MAAMoB,CAAY,EAGhC,GAA2C,YAAvCJ,EAAapB,KAAKuB,iBAClB,OAAOH,EAAapB,KAGxB,MAAM,IAAII,MAAM,6BAA6BgB,EAAapB,KAAKuB,gBAAkB,CACrF,EAEMG,wBAA0B3B,MAAO4B,IAC7B3B,EAAO,CACT4B,yBAA0BC,mBAAmBF,CAAsB,CACvE,EACMG,EAASf,MAAMjB,eAAeE,EAAM,oBAAoB,EAC9D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdC,SAAUN,EAAOM,SACjBC,gBAAiBP,EAAOP,gBAC5B,CACJ,EAEMe,kBAAoBvC,MAAOgC,EAAWQ,KACxC,IAAMrC,EAAYqC,EAAYrC,UACxBF,EAAO,CACTgC,WAAYD,EACZS,cAAeD,EAAYE,aAC3BC,WAAYH,EAAYI,UACxBT,QAASU,aAAaC,QAAQ,iBAAiB,EAC/CC,KAAMP,EAAYQ,UAClBC,QAAST,EAAYU,gBACrBC,KAAMX,EAAYY,SAClBC,UAAW,QACf,EAEA,MAAO,CACHC,QAFWtC,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,GAE5CoD,OACnB,CACJ,EAEMC,yBAA2BxD,MAAOG,EAAW6B,EAAWsB,EAAQL,EAASP,EAAce,EAAS,YAC5FxD,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfa,QAASD,EACTL,QAASA,EACTQ,OAAQA,CACZ,EAEA,MAAO,CACHC,WAFW1C,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,GAE5CwD,UACtB,CACJ,EAEMC,qBAAuB5D,MAAO6D,IAChC,IAAM1D,EAAY0D,EAASC,OAAO3D,UAC5BF,EAAO,CACTgC,WAAY4B,EAAS7B,UACrBS,cAAeoB,EAASC,OAAOpB,aAC/BqB,WAAYF,EAASC,OAAO3D,UAC5BwD,WAAYE,EAASH,UACrBM,SAAUH,EAASI,SACnBC,KAAML,EAASM,WACfC,iBAAkBP,EAASQ,eAC/B,EACerD,MAAMjB,eAAeE,EAAM,iBAAkBE,CAAS,CAEzE,EAEMmE,oBAAsBtE,MAAO0C,EAAcvC,EAAWiC,EAAOmC,EAAUC,KACrEvE,EAAO,CACPwC,cAAeC,EACfqB,WAAY5D,EACZsE,iBAAkBrC,CACtB,EACIA,GAASmC,IACTtE,EAAKmC,MAAQA,EACbnC,EAAK8C,KAAOwB,GAEVxC,EAASf,MAAMjB,eAAeE,EAAM,mBAAmB,EAC7D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdsC,cAA+C,IAAhC3C,EAAO4C,qBACtBC,iBAAkB7C,EAAOL,kBACzBY,gBAAiBP,EAAOP,iBACxBqD,mBAAoB9C,EAAO4C,oBAC/B,CACJ,EAEMG,iBAAmB9E,MAAOoC,EAAO2C,KAC7B9E,EAAO,CACTmC,MAAOA,EACP2C,SAAUA,CACd,EACMhD,EAASf,MAAMjB,eAAeE,EAAM,gBAAgB,EAC1D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdsC,cAA+C,IAAhC3C,EAAO4C,qBACtBC,iBAAkB7C,EAAOL,kBACzBY,gBAAiBP,EAAOP,iBACxBqD,mBAAoB9C,EAAO4C,oBAC/B,CACJ,EAEMK,kBAAoBhF,MAAOG,IAC7B,IAAM6B,EAAYa,aAAaC,QAAQ,oBAAoB,EACxDd,GAAa7B,IACNF,EAAO,CACTgC,WAAYD,CAChB,EAG+B,aADhBhB,MAAMjB,eAAeE,EAAM,mBAAoBE,CAAS,GAC7DqB,oBACNqB,aAAaoC,WAAW,eAAe,EACvCpC,aAAaoC,WAAW,oBAAoB,EAC5CpC,aAAaoC,WAAW,iBAAiB,EACzCpC,aAAaqC,QAAQ,2BAA4B,GAAG,EAGhE,EAEMC,gBAAkBnF,MAAO0C,EAAcV,EAAW7B,EAAWyC,EAAWV,KACpEjC,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfC,WAAYC,EACZS,UAAW,QACf,EACKnB,IACDjC,EAAKkC,QAAUD,GAGbkD,GADSpE,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,GAC1CiF,MAAMC,IAAIC,IAAQ,CACnChC,OAAQgC,EAAK/B,QACbP,UAAWsC,EAAKvC,KAChBwC,eAAgBD,EAAKE,QACrBC,YAAaH,EAAKI,QAClBC,oBAAqBL,EAAKM,gBAC1BxC,SAAUkC,EAAKnC,KACf0C,WAAYP,EAAK7B,MACpB,EAAC,EAIF,OAFAqC,sBAAsBV,CAAK,EAEpBA,CACX,EAGMW,wBAA0B/F,MAAOgC,EAAW7B,EAAWuC,EAAce,EAAS,YAC1ExD,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfe,OAAQA,CACZ,EAEA,OADezC,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,GACpD6F,SAASX,IAAIpC,IAAW,CAClCK,OAAQL,EAAQM,QAChBG,UAAWT,EAAQU,WACnBzB,OAAQe,EAAQd,QAChB8D,YAAahD,EAAQA,QACrBiD,YAAajD,EAAQuC,QACrB/B,OAAQR,EAAQQ,OAChB0C,WAAYlD,EAAQmD,SACvB,EAAC,CACN,EAEMC,eAAiBrG,MAAOgC,EAAWU,EAAcvC,EAAW+B,KACxDjC,EAAO,CACTgC,WAAYD,EACZS,cAAeC,CACnB,EACIR,IAAQjC,EAAKkC,QAAUD,GAErBH,EAASf,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,EAC/D,OAAO4B,EAAOuE,KA2BlB,EAEMC,kBAAoBvG,MAAO0C,EAAcvC,EAAW6B,EAAWE,EAAQsE,KACnEvG,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfP,QAASD,EACTuE,UAAWD,CACf,EAEA,OADAxF,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,EAC5C,CACHuG,QAAS,CAAA,CACb,CACJ,EAEMC,kBAAoB3G,UACtB,IACI,IACMC,EAAOe,MADDA,MAAMC,MAAM,yDAAyD,GAC1DK,KAAK,EAE5B,OAAkB,EAAdrB,EAAK2G,QAAc3G,EAAK,GAAG4G,UAC3BhE,aAAaqC,QAAQ,sBAAuBjF,EAAK,GAAG4G,QAAQ,EACrD5G,EAAK,GAAG4G,UAGZ,IAGX,CAFE,MAAOC,GACL,OAAO,IACX,CACJ,EAGA9G,eAAe+G,iBAAiBnF,EAAwBkC,GACvD,IAAM/B,EAASf,MAAMW,wBAAwBC,CAAsB,EAO7DoF,GALNnE,aAAaqC,QAAQ,gBAAiBnD,EAAOK,KAAK,EAClDS,aAAaqC,QAAQ,qBAAsBnD,EAAOC,SAAS,EAC3Da,aAAaqC,QAAQ,kBAAmBnD,EAAOG,MAAM,EAG9BW,aAAaC,QAAQ,sBAAsB,GAClE,GAAI,CAACkE,EAAgB,MAAM,IAAI3G,MAAM,sBAAsB,EAE3DM,IAAIsG,EACJ,IACCA,EAAcC,KAAKC,MAAMH,CAAc,CAGxC,CAFE,MAAOlG,GACR,MAAM,IAAIT,MAAM,2BAA2B,CAC5C,CAGMmC,EAAc,CACnBQ,UAAWiE,EAAYG,cAAgB,WACvClE,gBAAiB+D,EAAYI,aAAe,GAC5CC,aAAcL,EACdvE,aAAcoB,EAAOpB,aACrBE,UAAWkB,EAAOlB,UAClBzC,UAAW2D,EAAO3D,UAClBiD,SAAU8D,KAAKK,UAAUN,CAAW,CACrC,EAGMO,EAAcxG,MAAMyG,iBAAiB1F,EAAOC,UAAWQ,CAAW,EAKxE,OAHAK,aAAaoC,WAAW,sBAAsB,EAGvCuC,CACR,CAEAxH,eAAe0H,oBAAoB5D,EAAQsB,EAAOuC,GAC9C,IACU3F,EADV,GAAmB,EAAfoD,EAAMwB,OAMN,OALM5E,EAAYa,aAAaC,QAAQ,oBAAoB,EAKpD,CACHkD,SALahF,MAAM+E,wBAAwB/D,EAAW8B,EAAO3D,UAAW2D,EAAOpB,YAAY,EAM3F4D,MALUtF,MAAMqF,eAAerE,EAAW8B,EAAOpB,aAAcoB,EAAO3D,SAAS,EAMxF0F,WALiBT,EAAMwC,KAAKC,GAAQ,CAACA,EAAKvE,QAAW,CAACqE,CAAmB,GAKlD9B,UAClB,CAER,CAEA7F,eAAe8H,eAAehE,GAC5B,IAAM9B,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDiF,EAAgBlF,aAAaC,QAAQ,iBAAiB,EAC5D,GAAGiF,EAEF,OADc/G,MAAMqF,eAAerE,EAAW8B,EAAOpB,aAAcoB,EAAO3D,UAAW4H,CAAa,GACrF,IAAM,EAEtB,CAEA/H,eAAeyH,iBAAiBzF,EAAWQ,GAC1C,IACC,IAEgBwF,EAFVjG,EAASf,MAAMuB,kBAAkBP,EAAWQ,CAAW,EAQ7D,OAPIT,GAAUA,EAAOuB,QAAUd,EAAYU,kBAC3B8E,4EAAiFC,OAAOC,SAASC,iDAAiDF,OAAOC,SAASC,uBACjLnH,MAAMoH,eAAe,CACpB1F,aAAcF,EAAYE,aAC1BvC,UAAWqC,EAAYrC,SACxB,EAAG4B,EAAOuB,OAAQd,EAAYU,gBAAgB8E,CAAI,GAE5CjG,CAGR,CAFE,MAAO+E,GACR,MAAMA,CACP,CACD,CAEA9G,eAAeoI,eAAetE,EAAQR,EAAQ+E,GAC7C,IAAMrG,EAAYa,aAAaC,QAAQ,oBAAoB,EAC3D,GAAI,CAACd,EAAW,MAAM,IAAI3B,MAAM,YAAY,EAC5C,GAAKyD,EAAOpB,cAAiBoB,EAAO3D,UACpC,OAAaqD,yBAAyBM,EAAO3D,UAAW6B,EAAWsB,EAAQ+E,EAAavE,EAAOpB,YAAY,EAD5D,MAAM,IAAIrC,MAAM,gBAAgB,CAEhF,CAEA,SAASiI,aAAaxE,GACrB,IAGMpB,EACAV,EACAE,EALN,OAAKW,aAAaC,QAAQ,oBAAoB,GAGxCJ,EAAeoB,EAAOpB,aACtBV,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDZ,EAASW,aAAaC,QAAQ,iBAAiB,EAC9CqC,gBAAgBzC,EAAcV,EAAW8B,EAAO3D,UAAW2D,EAAOlB,UAAWV,CAAM,GALlF,EAMT,CAEAlC,eAAeuI,YAAYzE,GAC1B,IAGMpB,EACAV,EAJN,OAAKa,aAAaC,QAAQ,oBAAoB,GAGxCJ,EAAeoB,EAAOpB,aACtBV,EAAYa,aAAaC,QAAQ,oBAAoB,GACzC9B,MAAMmE,gBAAgBzC,EAAcV,EAAW8B,EAAO3D,UAAW2D,EAAOlB,SAAS,GAG/D4F,OAAOlD,GAC7BA,EAAKlC,QACf,GATI,EAYT,CAEA,SAASqF,WAAWC,GAMlB,GAAI,CAACA,EAAS,MAAO,CAAEC,KAAM,GAAIC,KAAM,EAAG,EAC1CjI,IAAIkI,EAQJ,OANCA,EADGH,CAAAA,EAAQI,SAAS,GAAG,GAEbJ,EAAQI,SAAS,GAAG,EACpB,IAAIC,KAAKL,EAAQM,QAAQ,IAAK,GAAG,CAAC,EAElC,IAAID,KAAKL,CAAO,EAEvBO,MAAMJ,EAAQK,QAAQ,CAAC,EAAU,CAAEP,KAAM,GAAIC,KAAM,EAAG,GAGpDO,EAAgBN,EAAQO,kBAAkB,EASzC,CAAET,KA1BM,CACd,UAAW,WAAY,QAAS,QAAS,MAAO,OAChD,OAAQ,SAAU,YAAa,UAAW,WAAY,aAgBnDU,EAAe,IAAIN,KAAKF,EAAQK,QAAQ,EAAoB,IAAhBC,CAAqB,GAEnCG,SAAS,GAE9B,IADDD,EAAaE,QAAQ,EAKlBX,KAHDS,EAAaG,SAAS,EAAEC,SAAS,EAAEC,SAAS,EAAG,GAAG,EAEnD,IADGL,EAAaM,WAAW,EAAEF,SAAS,EAAEC,SAAS,EAAG,GAAG,CAEhD,EACtB,CAEA,SAASE,qBAAqB9F,EAAQR,GACnBT,aAAaC,QAAQ,oBAAoB,EAA3D,IAiBM7C,EAfL,CACC,CACCqD,OAAU,IACVuG,uBAA0B,uGAC1BC,eAAkB,oCACnB,GAUyBlC,KAAK,GAAamC,EAAQzG,SAAWA,CAAM,EACtE,OAAgBlD,KAAAA,IAATH,EAPN,CACCqD,OAAU,KACVuG,uBAA0B,KAC1BC,eAAkB,aACnB,EAGyC7J,CAC3C,CAEA,SAAS+J,uBAAuBC,EAAkBC,GACjD,WAAYD,KAAoBC,IACjC,CAGA,SAASC,aAAaC,GACrB,GAAIA,GAAUA,EAAOC,OAAQ,CAC5B,GAA6B,UAAzB,OAAOD,EAAOC,QAAuBD,EAAOC,OAAOC,EACtD,OAAOF,EAAOC,OAAOC,EACf,GAA6B,UAAzB,OAAOF,EAAOC,OACxB,OAAOD,EAAOC,MAEhB,CACA,OAAO,IACR,CAGA,SAASE,cAAcH,GACtB,GAAIA,EAAQ,CACX,GAAIA,EAAOrH,MAAoC,EAA5BqH,EAAOrH,KAAKyH,KAAK,EAAE5D,OACrC,OAAOwD,EAAOrH,KACR,GAAIqH,EAAOhI,OAAsC,EAA7BgI,EAAOhI,MAAMoI,KAAK,EAAE5D,OAC9C,OAAOwD,EAAOhI,KAEhB,CACA,MAAO,gBACR,CAEA,SAASqI,aAAajI,GACrB,IAAMkI,EAAYlI,EAAYkI,UACxBC,EAAWnI,EAAYmI,SACvBjI,EAAeF,EAAYE,aAC3BvC,EAAYqC,EAAYrC,UACxBqE,EAAUhC,EAAY8E,aAAa9C,SAA6CyD,OAAOC,SAASC,KA4BrG,OA1B0B,GAAyB7D,oBAAoB5B,EAAcvC,EAAWuK,EAAWC,EAAUnG,CAAO,EAC3HoG,KAAK7J,IACL,GAAIA,EAAS2D,cACZmG,SAASC,cAAc,qEAAqE,EAAEC,UAAYC,WAAW,2DAA2D,EAChLH,SAASC,cAAc,4EAA4E,EAAEG,UAAUC,OAAO,QAAQ,EAC9HL,SAASM,eAAe,mCAAmC,EAAEC,MAAM,OAC7D,GAAIrK,EAASiB,UACnBa,aAAaqC,QAAQ,qBAAsBnE,EAASiB,SAAS,EAC7Da,aAAaqC,QAAQ,kBAAmBnE,EAASmB,MAAM,EACvDW,aAAaqC,QAAQ,gBAAiBnE,EAASqB,KAAK,EACpDiJ,WAAW3I,EAAcvC,CAAS,MAC5B,CAAA,GAAIY,EAA6B,YAA7BA,EAASuB,iBAAiCvB,EAAS6D,kBAAuD,EAAnC7D,EAAS6D,iBAAiBgC,QAQ3G,MAAM,IAAIvG,MAAM,kCAAkC,EAPjB,kCAA7BU,EAAS6D,mBACZ7D,EAAS6D,iBAAmB,+DAEM,YAA/B,OAAO0G,GACVA,EAAoBvK,EAAS6D,iBAAkB,QAAQ,CAIzD,CACD,CAAC,EACA2G,MAAMzK,IACN,MAAMA,CACP,CAAC,CAGH,CAEA,SAAS0K,UAAUhJ,GAClB,IAAMkI,EAAYlI,EAAYkI,UACxBe,EAAejJ,EAAYiJ,aAEjC,OAAO,GAAyB3G,iBAAiB4F,EAAWe,CAAY,EACtEb,KAAK7J,IACL,GAAIA,EAASiB,UACZa,aAAaqC,QAAQ,qBAAsBnE,EAASiB,SAAS,EAC7Da,aAAaqC,QAAQ,kBAAmBnE,EAASmB,MAAM,EACvDW,aAAaqC,QAAQ,gBAAiBnE,EAASqB,KAAK,MAC7C,CAAA,GAAIrB,EAA6B,YAA7BA,EAASuB,iBAAiCvB,EAAS6D,kBAAuD,EAAnC7D,EAAS6D,iBAAiBgC,QAK5G,MAAM,IAAIvG,MAAM,kCAAkC,EAJf,YAA/B,OAAOiL,GACVA,EAAoBvK,EAAS6D,iBAAkB,QAAQ,CAIzD,CACD,CAAC,EACA2G,MAAMzK,IACN,MAAMA,CACP,CAAC,CACH,CAEA,SAASuK,WAAW3I,EAAcvC,GACjC,IAAM6B,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDZ,EAASW,aAAaC,QAAQ,iBAAiB,EAC/C0D,EAAWkF,KAAKC,eAAe,EAAEC,gBAAgB,EAAEC,SAEzD,OAAOtF,kBAAkB7D,EAAcvC,EAAW6B,EAAWE,EAAQsE,CAAQ,CAC9E,CAEA,SAASsF,gBAAgBC,GACxB,IACC,IAGMC,EACAC,EAEAC,EAMAC,EAZN,OAAKJ,GAAsB,KAAfA,EAAIvB,KAAK,GAIfyB,GADAD,EAAI,IAAInL,IAAIkL,CAAG,GACJK,KAIO,KAFlBF,EAAWF,EAAEK,SAASC,MAAM,GAAG,EAAE9D,OAAO+D,OAAO,GAExC3F,OACLqF,IAGFE,EAAWD,EAASM,QAAQ,GACzBC,KAAKR,CAAM,EACbE,EAASO,KAAK,KAAK,IAblB,EAgBT,CAFE,MAAO5L,GACR,MAAO,EACR,CAED,CAEA,SAAS6L,gBAAgBC,GACxB,IAOMC,EAAShC,SAASM,eAAe,mBAAmB,EAC1D0B,EAAOC,QAAU,CAAA,EACjBD,EAAOE,iBAAiB,QATH,KACpB,IAAMC,EAAQC,WAAW,KACxBpK,aAAaqC,QAAQ,2BAA4B,GAAG,EACpD0H,EAAYM,KAAK,EACjBC,aAAaH,CAAK,CACnB,EAAG,GAAG,CACP,CAG6C,CAC9C,CAEA,SAASI,8BACR,IACOC,EADHxK,aAAaC,QAAQ,oBAAoB,GAMtCuK,EAAKxC,SAASM,eAAe,8CAA8C,KAC1EkC,EAAGC,MAAMC,QAAU,SANpBF,EAAKxC,SACTM,eAAe,6CAA6C,EAC5DqC,QAAQ,qCAAqC,KACvCH,EAAGC,MAAMC,QAAU,OAK7B,OAKME,uBACFrG,aAAe,GACfE,aAAe,GACfoG,cAAgB,KAChB5J,OAAS,GACT6D,oBAAsB,EACtBgG,0BAA4B,EAC5BC,uBAAyB,EACzBC,aAAe,GACfC,aAAe,GAKfC,YAAYzG,EAAc0G,GACtBC,KAAK3G,aAAeA,GAAgB,GACpC2G,KAAK7G,aAAeE,GAAcF,cAAgB,GAClD6G,KAAKC,KAAKF,CAAI,EACdC,KAAKH,aAAe,CAChBK,sBAAuB,CAACtL,aAAaC,QAAQ,UAAU,EAAI,uEAAyE,gCACpIsL,kBAAmBC,iBAAiBC,aAAa,mBAAmB,EACpEC,iBAAkBF,iBAAiBC,aAAa,kBAAkB,EAClEE,SAAUH,iBAAiBC,aAAa,UAAU,EAClDG,aAAcJ,iBAAiBC,aAAa,cAAc,EAC1DI,YAAaL,iBAAiBC,aAAa,aAAa,EACxDK,gBAAiBN,iBAAiBC,aAAa,iBAAiB,EAChEM,kBAAmBP,iBAAiBC,aAAa,mBAAmB,EACpEO,iBAAkBR,iBAAiBC,aAAa,kBAAkB,EAClEQ,gBAAiBT,iBAAiBC,aAAa,iBAAiB,EAChES,yBAA0BV,iBAAiBC,aAAa,0BAA0B,EAClFU,eAAgBX,iBAAiBC,aAAa,gBAAgB,EAC9DW,gBAAiBZ,iBAAiBC,aAAa,iBAAiB,EAChEY,cAAeb,iBAAiBC,aAAa,eAAe,CAChE,EACAL,KAAKkB,aAAe,IAAIC,aAAanB,KAAKoB,UAAU,CACxD,CAKAnB,WAAWF,GACPC,KAAKnK,OAASmK,KAAKqB,UAAU,EAG7B,IAAMC,EAAY,IAAIC,gBAAgBvH,OAAOC,SAASuH,MAAM,EACtDC,EAAaH,EAAUI,IAAI,0BAA0B,EAC3D,GAAID,EACA,IAEI,IAAMlI,EAAcxG,MAAM+F,iBAAiB2I,EAAYzB,KAAKnK,MAAM,EAQ5D8L,GAPN3B,KAAKJ,aAAe7M,MAAMuH,YAAY0F,KAAKnK,MAAM,EAEjDmK,KAAKtG,oBAAsBH,EAAYlE,OAEvCuM,yBAAyB,EADzB7B,EAAO,iBACuB,EAE9BuB,EAAUO,OAAO,0BAA0B,EAC5B7H,OAAOC,SAASmE,UAAYkD,EAAU9F,SAAS,EAAI,IAAM8F,EAAU9F,SAAS,EAAI,KAC/FxB,OAAO8H,QAAQC,aAAa,GAAInF,SAASoF,MAAOL,CAAM,CAG1D,CAFE,MAAO9I,GACLmH,KAAKiC,wBAAwB,2BAA6BpJ,EAAI1F,QAAS,OAAO,CAClF,KACG,CAEG+O,EAAiBtN,aAAaC,QAAQ,0BAA0B,GAClEqN,CAAAA,GAAmBlC,KAAK7G,eAAkB+I,IAC1ClC,KAAKJ,aAAe7M,MAAMuH,YAAY0F,KAAKnK,MAAM,EAEzD,CAGAnD,IAAIyP,EAEAC,6BAA6B,EAC7BD,EAAyB,CAAA,EAEZ,gBAATpC,IACAoC,EAAyBpP,MAAMsP,gCAC3BrC,KAAKJ,aACLI,KAAKnK,MACT,GAGRyM,2BAA2BtC,KAAKJ,YAAY,EAEvC2C,wBAAwB,GACzBX,yBAAyB,CAAA,CAAI,EAG7BO,GAEAP,yBAAyB,CAAA,CAAK,EAElC5B,KAAKP,cAAgB1M,MAAMiN,KAAKwC,oBAAoBzC,CAAI,EACxDC,KAAKyC,4BAA4B,CACrC,CAEApB,YACI,IAAMqB,EAAS9F,SAASC,cAAc,uCAAuC,EAC7E,GAAK,CAAE6F,GAAU,CAAEA,EAAOC,IACtB,MAAM,IAAIvQ,MAAM,qBAAqB,EAGnC0L,EAAM,IAAIlL,IAAI8P,EAAOC,GAAG,EAC1B9M,EAAS+M,OAAOC,YAAY/E,EAAIgF,aAAaC,QAAQ,CAAC,EAC1D,GAAK,CAAElN,EACH,MAAM,IAAIzD,MAAM,4BAA4B,EAEhD,GAAOyD,EAAOpB,cAAkBoB,EAAO3D,WAAe2D,EAAOlB,UAI7D,OAAOkB,EAHH,MAAM,IAAIzD,MAAM,sCAAsC,CAI9D,CAKA4Q,uBACI,IAAMC,EAAerG,SAASM,eAAe,mCAAmC,EAE5E+F,GACAA,EAAanE,iBAAiB,QAAS/M,UAEnC,IAAMmR,EAAmBtG,SAASM,eAAe,2BAA2B,EACtEnI,EAAYmO,EAAiBC,MACnC,GAAOpO,EAAP,CAQA,IAAMqO,EAAyBxG,SAASM,eAAe,iCAAiC,EAClFjI,EAAkBmO,EAAuBD,MAC/C,GAAOlO,EAAP,CAUAvC,IAAIgK,EAAW,GACXD,EAAY,GACZe,EAAe,GACnB,IAAM6F,EAAsBzG,SAASC,cAAc,4BAA4B,EAE/E,GAAKwG,GAAuBA,EAAoBrG,UAAUsG,SAAS,QAAQ,EAAI,CAC3E,IAAMC,EAAmB3G,SAASM,eAAe,gCAAgC,EACjF,IAAMsG,EAAkB5G,SAASM,eAAe,+BAA+B,EACzEuG,EAAsB7G,SAASM,eAAe,mCAAmC,EAGvF,GAAK,EADLT,EAAY8G,EAAiBJ,OAOzB,OALAI,EAAiBlE,MAAMqE,YAAc,MACrCH,EAAiBpG,MAAM,EADvBoG,KAEAA,EAAiBzE,iBAAiB,QAAS,WACvCkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,EAKL,GAAKH,GAAoBC,GAEhB,EADL9G,EAAW8G,EAAgBL,OAOvB,OALAK,EAAgBnE,MAAMqE,YAAc,MACpCF,EAAgBrG,MAAM,EADtBqG,KAEAA,EAAgB1E,iBAAiB,QAAS,WACtCkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,EAMT,GAAKH,GAAoBE,GAAuB,CAAED,GAEzC,EADLhG,EAAeiG,EAAoBN,OAO/B,OALAM,EAAoBpE,MAAMqE,YAAc,MACxCD,EAAoBtG,MAAM,EAD1BsG,KAEAA,EAAoB3E,iBAAiB,QAAS,WAC1CkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,CAKb,CAGA,IAAMH,EAAmB3G,SAASM,eAAe,gCAAgC,EACjFT,EAAY8G,EAAiBJ,MAGvBF,EAAerG,SAASM,eAAe,mCAAmC,EAI5E3I,GAHJ0O,EAAaU,SAAW,CAAA,EACxBV,EAAanG,UAAYC,WAAW,kBAAkB,EAEpC,CACdhI,UAAWA,EACXE,gBAAiBA,EAEjBoE,aAAc2G,KAAK3G,aACnB5E,aAAcuL,KAAKnK,OAAOpB,aAC1BE,UAAWqL,KAAKnK,OAAOlB,UACvBzC,UAAW8N,KAAKnK,OAAO3D,UACvBiD,SAAU8D,KAAKK,UAAU0G,KAAK3G,cAAmC,CAAC9C,QAAQ,mBAAmB,CAAC,CAClG,GAEKkG,IACDlI,EAAYkI,UAAYA,GAEvBC,IACDnI,EAAYmI,SAAWA,GAEtBc,IACDjJ,EAAYiJ,aAAeA,GAI/B5I,aAAaqC,QAAQ,uBAAwBgC,KAAKK,UAAU,CACxD,GAAG0G,KAAK3G,aACRD,YAAanE,CACjB,CAAC,CAAC,EAEFvC,IAAIkR,EACJ,IACIA,EAAmB7Q,MAAMiN,KAAK6D,WAAWtP,CAAW,CAIxD,CAHE,MAAO1B,GAEL,OADAmN,KAAAA,KAAKiC,wBAAwBpP,EAAMM,OAAO,CAE9C,CAGA8P,EAAaU,SAAW,CAAA,EACxBV,EAAa5D,MAAMyE,OAAS,UAEvBF,EAAiBG,cAKa5R,KAAAA,IAA9ByR,EAAiBI,WAClBhE,KAAK3G,aAAa2K,SAAWJ,EAAiBI,UAIlDhE,KAAKJ,aAAe7M,MAAMuH,YAAY0F,KAAKnK,MAAM,EAEjDyM,2BAA2BtC,KAAKJ,YAAY,EAE5CI,KAAK3G,aAAe,GACpBtG,MAAMiN,KAAKwC,oBAAoB,YAAY,EAC3CZ,yBAAyB,CAAA,CAAK,EAC9BqC,sBAAsB,CAAA,CAAK,EApH3B,MANIb,EAAuB/D,MAAMqE,YAAc,MAC3CN,EAAuBjG,MAAM,EAC7BiG,EAAuBtE,iBAAiB,QAAS,WAC7CkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,CARL,MANIR,EAAiB7D,MAAMqE,YAAc,MACrCR,EAAiB/F,MAAM,EACvB+F,EAAiBpE,iBAAiB,QAAS,WACvCkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,CAiIT,CAAC,CAET,CAMAlB,0BAA0BzC,EAAMmE,EAAsB,CAAA,GAClD,IAAMC,EAAkBvH,SAASC,cAAc,sBAAsB,EAAID,SAASC,cAAc,sBAAsB,EAAID,SAASwH,cAAc,KAAK,EACtJD,EAAgBE,UAAY,sBAC5BF,EAAgBG,UAAYvH,WAAW,EAAE,EACzCoH,EAAgBI,gBAAgB,OAAO,EAEvC7R,IAAI8R,EAAe,GACfC,EAEAC,EAAoB,GAExB,OAAQ3E,GACJ,IAAK,eACDyE,EAAe,eACfxE,KAAK2E,UAAYH,EACjBE,EAAoB,CAChBvL,aAAc6G,KAAK7G,aACnB+G,sBAAuB,CAACtL,aAAaC,QAAQ,UAAU,EAAI,uEAAyE,gCACpI+P,cAAehI,SAAS3C,SAAS4K,UAAY,GAC7C1E,kBAAmBC,iBAAiBC,aAAa,mBAAmB,EACpEG,aAAcJ,iBAAiBC,aAAa,cAAc,EAC1DC,iBAAkBF,iBAAiBC,aAAa,kBAAkB,EAClE,GAAGL,KAAKH,YACZ,EACAiF,wBAAwB,GAAKlD,yBAAyB,CAAA,CAAK,EAC3D,MACJ,IAAK,OACD,GAAImD,yBAAyB,EACzB,OAEJP,EAAe,OACfE,EAAoB,CAAC,GAAG1E,KAAKH,YAAY,EACzC,MACJ,IAAK,cACD2E,EAAe,cACfE,EAAoB,CAAC,GAAG1E,KAAKH,YAAY,EACzC,MACJ,IAAK,aACD2E,EAAe,aACfxE,KAAK2E,UAAYH,EACjBE,EAAoB,CAChBxE,sBAAuB,CAACtL,aAAaC,QAAQ,UAAU,EAAI,uEAAyE,gCACpI,GAAGmL,KAAKH,YAAY,EACxB,MACJ,IAAK,YACD2E,EAAe,YACf,IAAMQ,EAAgBpQ,aAAaC,QAAQ,qBAAqB,EAChE6P,EAAoB,CAChBO,eAAgBD,EAAgB,mBAAqBA,EAAgB,IAAM,GAC3E5I,OAAQgE,iBAAiBC,aAAa,YAAY,EAClD6E,QAAS9E,iBAAiBC,aAAa,SAAS,EAChD8E,SAAU/E,iBAAiBC,aAAa,UAAU,EAClD+E,gBAAiBhF,iBAAiBC,aAAa,iBAAiB,EAChEgF,sBAAuBjF,iBAAiBC,aAAa,uBAAuB,EAC5E3D,SAAU,QACVvI,MAAO,GACP,GAAG6L,KAAKH,YAAY,EACxB,MACJ,IAAK,iBACD2E,EAAe,iBACfxE,KAAK2E,UAAYH,EAEjBxE,KAAKL,uBAAyB2F,MAAMC,QAAQvF,KAAKJ,YAAY,EAAII,KAAKJ,aAAajH,OAAS,EAE5FqH,KAAKN,0BAA4B4F,MAAMC,QAAQvF,KAAKJ,YAAY,EAC1DI,KAAKJ,aAAarF,OAAOlD,IACvB,IAEI,OADaA,EAAKlC,SAAW8D,KAAKC,MAAM7B,EAAKlC,QAAQ,EAAI,IAC7CoB,UAAYyD,OAAOC,SAASC,IAChB,CAA1B,MAAOsL,GAAK,MAAO,CAAA,CAAO,CAChC,CAAC,EAAE7M,OACD,EAEN+L,EAAoB,CAChBxM,WAAY,MACZuN,cAAe,GACfvF,sBAAuB,CAACtL,aAAaC,QAAQ,UAAU,EAAI,uEAAyE,gCACpI6Q,cAAe3J,uBAAuBiE,KAAKN,0BAA2BM,KAAKL,sBAAsB,EACjG,GAAGK,KAAKH,YACZ,CAIR,CAOA,OANAsE,EAAgBG,UAAYtE,KAAK2F,aAAanB,EAAcE,CAAiB,EAC7E9H,SAAS3J,KAAK2S,YAAYzB,CAAe,EAGzC0B,wBAAwB,EAEhB9F,GACJ,IAAK,eAED,IAAM+F,EAAY9L,OAAO+L,aAAa,EAChCC,EAAkB,CAAC,CAACpR,aAAaC,QAAQ,oBAAoB,EAC7DV,EAAQS,aAAaC,QAAQ,eAAe,EAE9CmR,GAAmB7R,GAAS,CAACA,EAAM0G,SAAS,UAAU,GACtD+B,SAASC,cAAc,4BAA4B,EAAEG,UAAUiJ,IAAI,QAAQ,EAGxD,UAAnBH,EAAU/F,OAGVmG,wBADqBC,uBAAuBL,CAAS,EAChBM,QAAQ,EAC7CpG,KAAKqG,wBAAwB,GAGjCrG,KAAKgD,qBAAqB,EAC1B,MACJ,IAAK,OACDjQ,MAAMiN,KAAKsG,aAAa,EACxB1J,SAASC,cAAc,2BAA2B,EAAEiC,iBAAiB,QAAS,IACpEyH,EAAuBf,EAAEgB,cAAcxJ,UACzCuJ,GAAwB,CAACA,EAAqBjD,SAAS,QAAQ,GAC/DtD,KAAKwC,oBAAoB,YAAY,CAE7C,CAAC,EACDyB,sBAAsB,CAAA,CAAK,EAC3B,MACJ,IAAK,cACDrH,SAASC,cAAc,6BAA6B,EAAEiC,iBAAiB,QAAS,IAC5E2H,kBAAkBzG,KAAK3G,aAAc,cAAc,CACvD,CAAC,EACD,MACJ,IAAK,aACKqN,EAAY9J,SAASC,cAAc,gCAAgC,EAElE,CAACjI,aAAaC,QAAQ,UAAU,EAC/B6R,EAAU1J,UAAUiJ,IAAI,wCAAwC,EAEhES,EAAU1J,UAAUC,OAAO,wCAAwC,EAGvE4I,wBAAwB,EAC5BnT,IAAIiU,EAAuB,EACtB3G,KAAKJ,cAAcjH,SACpBqH,KAAKJ,aAAe7M,MAAMuH,YAAY0F,KAAKnK,MAAM,GAErD,IAAMsB,EAAQ6I,KAAKJ,aAEfgH,GADJnC,EAAmB1R,MAAM0G,oBAAoBuG,KAAKnK,OAAQsB,EAAO6I,KAAKtG,mBAAmB,EAC9D,IAC3B,GAAmB,EAAfvC,EAAMwB,OAAY,CAClB,IAAMkO,EAAa7M,OAAOC,SAASC,KACnC,IAAM4M,EAAc3P,EAAM4P,KAAK,CAACC,EAAGC,KACzBC,EAAUjO,KAAKC,MAAM8N,EAAE7R,QAAQ,EAAEoB,UAAYsQ,EAAa,EAAI,EAEpE,OADgB5N,KAAKC,MAAM+N,EAAE9R,QAAQ,EAAEoB,UAAYsQ,EAAa,EAAI,GACnDK,CACrB,CAAC,EAEDtK,SAASC,cAAc,2CAA2C,EAAEyH,UAAY,GAEhF,IAAK5R,IAAIyU,EAAI,EAAGA,EAAIL,EAAYnO,OAAQwO,CAAC,GAAI,CACzC,IAAMC,EAASN,EAAYK,GAGrB9R,EAAS+R,EAAO/R,OAChBN,EAAYqS,EAAOrS,UACnBsS,EAAiBD,EAAOjS,SAC9BzC,IAAI4U,EAAW,KACf,GAAID,EACA,KACIC,EAAWrO,KAAKC,MAAMmO,CAAc,GAC3BE,QAAgC,SAAtBH,EAAOxP,WAC1B0P,EAASjS,OAAS+R,EAAO/R,MAG7B,CAFE,MAAOxC,GACLyU,EAAW,IACf,CAEJ,IAsBUE,EAEAC,EAxBJC,EAAiBJ,EAAWA,EAAS/Q,QAAU,GAC/CoR,EAAeL,EAAWA,EAASlB,SAAW,GAGpD1T,IAAIkV,EAAyB,GACzBC,EAAuB,4BACvBP,GAAkCnV,KAAAA,IAAtBmV,EAAStD,WAGjB6D,EAFAP,EAAStD,UACT4D,EAAyB5H,KAAKH,aAAakB,eACpB,uBAEvB6G,EAAyB5H,KAAKH,aAAamB,gBACpB,sEAI5B0G,IAAmB1N,OAAOC,SAASC,MAClCyM,CAAoB,GAGnBzC,GAAuBwD,IAAmB1N,OAAOC,SAASC,OAIrDuN,EAAaK,cAFbN,EAAkBO,mBAAmBtD,EAAkBpP,CAAM,CAEnB,EAC1C2S,EAA8B,CAChCjT,UAAWA,GAAa,GACxB6G,uBAAwB4L,EAAgB5L,uBACxCC,eAAgB2L,EAAgB3L,eAChC+L,uBAAwBA,EACxBC,qBAAsBA,EACtBI,gBAAiBlL,WAAWyK,EAAgBU,eAAe,EAC3DC,YAAaT,EACbzG,cAAejB,KAAKH,aAAaoB,cACjCmH,qBAAsBvK,gBAAgB6J,CAAc,EACpDpQ,eAAgBkQ,EAAgBa,gBAChCjC,SAAUpG,KAAKsI,iBAAiBX,CAAY,EAC5CtS,OAAQA,EACRkT,eAAgBd,EAAWc,eAC3BC,YAAaf,EAAWe,YACxBC,mBAAoBhB,EAAWgB,mBAC/BC,cAAejB,EAAWiB,cAC1BC,YAAa,GACbC,kBAAyC,SAAtBxB,EAAOxP,WAAwB,GAAK,qCACvDiR,gBAAuC,SAAtBzB,EAAOxP,WAAwB,GAAKoI,KAAK2F,aAAa,WAAW,CACtF,EAE+BmD,oCAAoCtB,EAAgBnS,MAAM,IAErF2S,EAA4BW,YAAc,UAE9C/L,SAASC,cAAc,2CAA2C,EAAEyH,WAAatE,KAAK2F,aAAa,cAAeqC,CAA2B,EAExIhI,KAAK+I,0BAA0BzB,CAAQ,GACxCV,EAAqBpI,KAAK8I,CAAQ,EAG9C,CACAtH,KAAKN,0BAA4BiH,EACjC3G,KAAKL,uBAAyBxI,EAAMwB,OACpCqQ,yBAAyBpC,EAAsB5G,IAAI,EACnDpD,SAASC,cAAc,kCAAkC,EAAEyH,WAAavH,WAAW,IAAMhB,uBAAuBiE,KAAKN,0BAA2BM,KAAKL,sBAAsB,CAAC,CAChL,CAEqB,IAAjBxI,EAAMwB,SACNiE,SAASC,cAAc,2CAA2C,EAAEyH,UAAYvH,WAAW,mFAAmF,GAIlLiD,KAAKiJ,gBAAgB,EACrBhF,sBAAsB,CAAA,CAAK,EAC3B,MACR,IAAK,YAEGvF,gBAAgBsB,IAAI,EACpBb,4BAA4B,EAEtB+J,EAAOnW,MAAM8G,eAAemG,KAAKnK,MAAM,EACvCsT,EAAmBpW,MAAM2F,kBAAkB,EAE3C0Q,EAAUxU,aAAaC,QAAQ,qBAAqB,GAAKsU,EAG/DzE,EAAkBO,gBAFDmE,qBAA6BA,KAAa,KAEN,GAElDF,IACCxE,EAAkBhI,SAAWwM,EAAKpU,MAAQ,QAC1C4P,EAAkBvQ,MAAQ+U,EAAK/U,OAAS,GACrC+U,GAAM9M,QAAQiN,KAAG3E,EAAkBtI,OAAS8M,GAAM9M,QAAQiN,GAGjElF,EAAgBG,UAAYtE,KAAK2F,aAAa,YAAajB,CAAiB,EAC5E9H,SAAS3J,KAAK2S,YAAYzB,CAAe,EACzCzF,gBAAgBsB,IAAI,EACpBb,4BAA4B,EAE5B,MACR,IAAK,iBAEG,IAAM5K,EAAcxB,MAAMgV,mBAD1BtD,EAAmB1R,MAAM0G,oBAAoBuG,KAAKnK,OAAQmK,KAAKJ,aAAcI,KAAKtG,mBAAmB,EACtCsG,KAAKtG,mBAAmB,EAEjF4P,EAAoB1M,SAASC,cAAc,kCAAkC,EAC/EyM,IACAA,EAAkBxM,UAAYC,WAAWxI,EAAY2D,UAAU,GAGnEwM,EAAkBxM,WAAa3D,GAAa2D,WAC5CwM,EAAkBe,cAAgBlR,GAAakR,cAI/C/S,IAAI0T,EAAW,KACLmD,EAAkBvJ,KAAKJ,aAAajG,KAAK,GAAa6P,OAAO1N,EAAQzG,MAAM,IAAMmU,OAAOjV,EAAYc,MAAM,CAAC,EACjH3C,IAAIwC,EAAO,KAEX,GAAIqU,GAAmBA,EAAgBpU,SACnC,IACID,EAAO+D,KAAKC,MAAMqQ,EAAgBpU,QAAQ,EAC1CiR,EAAWlR,EAAKkR,UAAY,IACY,CAA1C,MAAOZ,GAAKY,EAAW,KAAMlR,EAAO,IAAM,CAGxDwP,EAAkByD,YAAcjT,EAAKqB,QACrC,IAAM6R,EAAuBlT,EAAKqB,QAAQwE,QAAQf,OAAOC,SAASwP,OAAQ,EAAE,EAkBlEC,GAjBVhF,EAAkB0D,qBAAuBA,EAAqBzP,OAAS,EACjEzD,EAAKqB,QAAQwE,QAAQf,OAAOC,SAAS0P,SAAW,IAAK,EAAE,EAAIvB,EAEjEjE,EAAgBG,UAAYtE,KAAK2F,aAAa,iBAAkBjB,CAAiB,EACjF9H,SAAS3J,KAAK2S,YAAYzB,CAAe,EAGjC0B,wBAAwB,EAEpB3Q,GAAQkR,IAER4C,yBAAyB,CAAC9T,GAAO8K,IAAI,EACE,YAAnC,OAAOkG,0BACPA,wBAAwBE,CAAQ,EAIZxJ,SAASC,cAAc,gDAAgD,GACnG+M,EAAkB,GAChBC,EAAejV,aAAaC,QAAQ,iBAAiB,EAE3D,GAAwC,EAAnCN,EAAYkR,cAAc9M,OAAa,CACxCmR,mCAAmCvV,EAAYc,MAAM,EACrDqU,EAAwBpF,UAAYvH,WAAW,EAAE,EACjD,IAAK,IAAM/H,KAAWT,EAAYkR,cAAe,CAE7C,IADAsE,EAAeC,OAAOH,CAAY,IAAMG,OAAOhV,EAAQiV,aAAa,EAC9DxC,EAAaK,cAAc,CAC7BlM,uBAAwB5G,EAAQkV,uBAChCrO,eAAgB7G,EAAQmV,iBAC5B,CAAC,EACKC,EAAc,CAChBD,kBAAmBnV,EAAQmV,kBAC3BnS,YAAahD,EAAQgD,YACrBC,YAAajD,EAAQiD,YACrBoS,YAAarV,EAAQqV,YACrBnS,WAAYwM,EAAkBxM,WAC9BqQ,eAAgBd,EAAWc,eAC3BC,YAAaf,EAAWe,YACxBC,mBAAoBhB,EAAWgB,mBAC/BC,cAAejB,EAAWiB,cAC1B4B,uBAAwBP,EAAe,QAAU,OACrD,EAC6C5X,KAAAA,IAAzCyX,EAAgB5U,EAAQiD,eACxB2R,EAAgB5U,EAAQiD,aAAe,IAGvC2R,EAAgB5U,EAAQiD,aAAauG,KAAK4L,CAAW,CAE7D,CACA1X,IAAI6X,EAAkB,GAEtB,IAAK,IAAMC,KAAOZ,EAAiB,CAC/BlX,IAGW+X,EAHPC,EAAqBd,EAAgBY,GACzC9X,IAAIiY,EAAyB,GAE7B,IAAWF,KADXC,EAAmB3D,KAAK,CAACC,EAAGC,IAAMD,EAAEqD,YAAYO,cAAc3D,EAAEoD,WAAW,CAAC,EACpDK,EAAoB,CACxChY,IAAImY,EAAkCH,EAAmBD,GACzDE,GAA0B3K,KAAK2F,aAAa,0BAA2BkF,CAA+B,CAC1G,CACAN,GAAmBvK,KAAK2F,aAAa,6BACjC,CACImF,mBAAoBN,EACpBO,mBAAoBJ,EACpB9B,gBAAkD,SAAjCpE,GAAkB7M,WAAwB,GAAKoI,KAAK2F,aAAa,eAAe,CACrG,CACJ,CACJ,CACA+D,EAAwBpF,UAAYiG,CACxC,MACIb,EAAwBpF,UAAYvH,WAAW,aAAa,EAI1DiO,EAAWpO,SAASC,cAAc,yCAAyC,EAE7E,SAASoO,IACgB,GAEjBjL,KAAKmD,MAAMxK,OACXqH,KAAKhD,UAAUiJ,IAAI,MAAM,EAEzBjG,KAAKhD,UAAUC,OAAO,MAAM,CAEpC,CATA+N,IAUAA,EAASlM,iBAAiB,QAASmM,CAAoB,EACvDD,EAASlM,iBAAiB,SAAUmM,CAAoB,GAI5DhH,sBAAsB,EAGtBjF,WAAW,KACP,IAAMkM,EAAmBtO,SAASC,cAAc,8BAA8B,EAC9EqO,EAAiBC,SAAS,CACtBC,IAAKF,EAAiBG,aACtBC,SAAU,QACd,CAAC,CACL,EAAG,CAAC,EAEJ,IAAMC,EAAa3O,SAASC,cAAc,0CAA0C,EACpF,GAAI0O,EAAY,CACZvL,KAAKkB,aAAajB,KAAK,EACvBvN,IAAI8Y,EAAcxL,KAClBuL,EAAWzM,iBAAiB,QAAS/M,MAAOyT,IACxCA,EAAEiG,eAAe,EAEjB,IACMC,EADuBH,EAAWhM,QAAQ,mCAAmC,EAChD1C,cAAc,yCAAyC,EAEpFzC,EAAcsR,EAAMvI,MAAM5G,KAAK,EACrC,GAAKnC,EAAL,CAIAsR,EAAM/H,SAAW,CAAA,EACjB4H,EAAW5H,SAAW,CAAA,EAEtBjR,IAAIiZ,EAAqB,KAEzB,IACIA,EAAqB5Y,MAAMoH,eAAe6F,KAAKnK,OAAQmK,KAAKtG,oBAAqBU,CAAW,EAC5FsR,EAAMvI,MAAQ,GACdpQ,MAAMiN,KAAKwC,oBAAoB,gBAAgB,EAC/CyB,sBAAsB,CAAA,CAAK,CAG/B,CAFE,MAAOpL,GACL+S,MAAM,gCAAkC/S,EAAI1F,OAAO,CACvD,CAEIqY,EAAYtK,aAAa2K,SAAS,GAA4B,OAAvBF,GAA+BA,EAAmBnZ,eAAe,WAAW,IAC7GuB,EAAYa,aAAaC,QAAQ,oBAAoB,GACrDiX,EAAwB/Y,MAAMyY,EAAYtK,aAAa6K,0BAA0BP,EAAY3V,OAAQ9B,EAAW4X,EAAmBlW,SAAS,GACvHgD,UACvB+S,EAAYtK,aAAa8K,UAAU,uDAAuD,EACpFC,EAAYhT,KAAKK,UAAUwS,CAAqB,EACtDI,QAAQC,IAAIF,CAAS,IAI7BP,EAAM/H,SAAW,CAAA,EACjB4H,EAAW5H,SAAW,CAAA,CA7BE,CA8B5B,CAAC,CACL,CAKR,CAEMyI,EAA4BxP,SAASC,cAAc,oCAAoC,EAC7F,IAAM2O,EAAcxL,KACfoM,GACDA,EAA0BtN,iBAAiB,QAAS,SAAS0G,EAAG6G,EAAOb,GACnEa,EAAK7J,oBAAoB,YAAY,CACzC,CAAC,EAGC8J,EAAsB1P,SAASC,cAAc,6CAA6C,EA+ChG,OA9CKyP,GACDtM,KAAKkB,aAAaqL,oBAAoBD,CAAmB,EAG7D1P,SAASC,cAAc,gCAAgC,GAAGiC,iBAAiB,QAAS,IAChFkB,KAAKf,KAAK,CACd,CAAC,EAEDrC,SAASC,cAAc,qBAAqB,GAAGiC,iBAAiB,QAAS,KACrEkB,KAAKwC,oBAAoB,WAAW,CACxC,CAAC,EAED5F,SAASC,cAAc,8CAA8C,GAAGiC,iBAAiB,QAAS,KAC9F/H,kBAAkBiJ,KAAKnK,OAAO3D,SAAS,CAC3C,CAAC,EAED0K,SAASM,eAAe,kBAAkB,GAAG4B,iBAAiB,QAAS,KACnE0N,kBAAkB,CACtB,CAAC,EAED5P,SAASM,eAAe,yBAAyB,GAAG4B,iBAAiB,QAAS,KAC1E,IAAM4H,EAAY9J,SAASC,cAAc,gCAAgC,EAEtE,CAACjI,aAAaC,QAAQ,UAAU,GAAK6R,EAAU1J,UAAUsG,SAAS,wCAAwC,GACzG1O,aAAaqC,QAAQ,WAAY,GAAG,EACpCyP,EAAU1J,UAAUC,OAAO,wCAAwC,IAEnErI,aAAaqC,QAAQ,WAAY,GAAG,EACpCyP,EAAU1J,UAAUiJ,IAAI,wCAAwC,EAExE,CAAC,EAEDrJ,SAASC,cAAc,+CAA+C,GAAGiC,iBAAiB,QAAS,KAC/F0N,kBAAkB,CACtB,CAAC,EAED5P,SAASC,cAAc,sBAAsB,GAAGiC,iBAAiB,QAAS,KACtEkB,KAAKwC,oBAAoBxC,KAAK2E,SAAS,CAC3C,CAAC,EAQMR,CACX,CAEA8E,kBACIrM,SAAS6P,iBAAiB,aAAa,EAAEC,QAAQ9S,IAC7CA,EAAKkF,iBAAiB,QAAS/M,UAC3BW,IAAI0T,EAAW,KACf,IACIA,EAAWnN,KAAKC,MAAMU,EAAK+S,aAAa,gBAAgB,CAAC,CAG7D,CAFE,MAAO9Z,GACLuT,EAAW,IACf,CACIA,GACAF,wBAAwBE,CAAQ,EAEpCpG,KAAKtG,oBAAsBE,EAAK+S,aAAa,cAAc,EAC3D5Z,MAAMiN,KAAK4M,YAAY,CAC3B,CAAC,CACL,CAAC,CACL,CAQAA,oBACI7Z,MAAMiN,KAAKwC,oBAAoB,gBAAgB,EAC/C,IAAMqK,EAAoB7M,KAAK8M,qBAAqB9M,KAAKtG,mBAAmB,EAExEmT,IACAhH,wBAAwB,EACxBmD,yBAAyB,CAAC6D,GAAoB7M,IAAI,EAClDA,KAAKqG,wBAAwB,GAGjCpC,sBAAsB,CAAA,CAAK,CAC/B,CAWA0B,aAAanB,EAAcuI,EAAY,IACnCra,IAAIsa,EAAWC,uBAAuBC,gBAAgB1I,CAAY,EAElE,IAAK,GAAM,CAACnS,EAAK8Q,KAAUP,OAAOG,QAAQgK,CAAS,EAAG,CAC5CI,OAAmB9a,MACzBK,IAAI0a,EAOAA,EAFApN,KAAKqN,yBAAyBL,EAAUG,CAAW,EAErCnN,KAAKoB,WAAWoI,OAAOrG,CAAK,CAAC,EAG7BpG,WAAWyM,OAAOrG,CAAK,EAAG,CAAC6J,SAAUxI,EAAc8I,UAAW,CAAA,CAAI,CAAC,EAGrFN,EAAWA,EAASO,WAAWJ,EAAaC,CAAW,CAC3D,CAEA,OAAOrQ,WAAWiQ,EAAU,CAACA,SAAUxI,CAAY,CAAC,CACxD,CAQA6I,yBAAyBL,EAAUG,GAEzBK,EAAqBL,EAAYpS,QAAQ,QAAS,MAAM,EAY9D,OAPyB,IAAI0S,oCACID,cAC7B,GACJ,EAIwBE,KAAKV,CAAQ,CACzC,CAEA5L,WAAa,GACFuM,EACF5S,QAAQ,KAAM,OAAO,EACrBA,QAAQ,KAAM,MAAM,EACpBA,QAAQ,KAAM,MAAM,EACpBA,QAAQ,KAAM,QAAQ,EACtBA,QAAQ,KAAM,QAAQ,EAG/BuL,qBACI,GAAI,CAAC1R,aAAaC,QAAQ,oBAAoB,EAC1C,MAAO,GAGX,IAAMJ,EAAeuL,KAAKnK,OAAOpB,aAC3BV,EAAYa,aAAaC,QAAQ,oBAAoB,EAErD+Y,EAAehZ,aAAaC,QAAQ,qBAAqB,EAE/DnC,IAAImb,EAQGA,EANa,IAAjBD,GAAuBA,EAMNA,GALF7a,MAAMmE,gBAAgBzC,EAAcV,EAAWiM,KAAKnK,OAAO3D,UAAW8N,KAAKnK,OAAOlB,SAAS,GAC7E4F,OAAOlD,GACxBA,EAAKlC,QACf,EAC0BwD,OAGzBmV,EAAmBlR,SAASM,eAAe,gCAAgC,EAC5E4Q,IACDA,EAAiBhR,UAAYC,WAAW8Q,CAAU,EAClDC,EAAiB9Q,UAAUC,OAAO,QAAQ,EAElD,CAYA4G,iBAAiBtP,GACRK,aAAaC,QAAQ,oBAAoB,IAC1C9B,MAAMyJ,aAAajI,CAAW,EAAEyL,KAAKiC,uBAAuB,EACvD1N,EAAYiJ,cACbzK,MAAMwK,UAAUhJ,CAAW,EAAEyL,KAAKiC,uBAAuB,GAIjE,IAAMlO,EAAYa,aAAaC,QAAQ,oBAAoB,EAE3D,OAAOd,EAIMyF,iBAAiBzF,EAAWQ,CAAW,EAFzC,CAACwP,YAAa,CAAA,CAAI,CAGjC,CAKA9E,OACI4G,wBAAwB,EACxB7F,KAAKwC,oBAAoB,MAAM,CAEnC,CAEAuL,gCAAgCjS,GAC5B,IAAMkS,EAAalS,EAAQmS,UAAU,EAC/BC,EAAUtR,SAASwH,cAAc,MAAM,EAM7C,OALA8J,EAAQ7J,UAAY,qDAEpBvI,EAAQqS,sBAAsB,cAAeD,CAAO,EACpDA,EAAQtI,YAAYoI,CAAU,EAEvBE,CACX,CAOApB,qBAAqBsB,GACjB,IAAM7E,EAAkBvJ,KAAKJ,aAAajG,KAAK,GAAamC,EAAQzG,OAAOmG,SAAS,IAAM4S,EAAe5S,SAAS,CAAC,EACnH,GAAI+N,GAAgDpX,KAAAA,IAA7BoX,EAAgBpU,SAAwB,CAC3DzC,IAAI2b,EAAsB,KAC1B,IACIA,EAAsBpV,KAAKC,MAAMqQ,EAAgBpU,QAAQ,CAG7D,CAFE,MAAOtC,GACLwb,EAAsB,IAC1B,CACA,GAA4B,OAAxBA,GAA+D,UAA/B,OAAOA,EACvC,OAAOA,CAEf,CACA,OAAO,IACX,CAEA5L,8BAEmB7F,SAAS6P,iBAAiB,4BAA4B,EAC9DC,QAAQhB,IACPA,EAAMvI,OACNuI,EAAM1O,UAAUiJ,IAAI,WAAW,EAGnCyF,EAAM5M,iBAAiB,QAAS,KACxB4M,EAAMvI,MACNuI,EAAM1O,UAAUiJ,IAAI,WAAW,EAE/ByF,EAAM1O,UAAUC,OAAO,WAAW,CAE1C,CAAC,EAEDyO,EAAM5M,iBAAiB,OAAQ,KACtB4M,EAAMvI,OACPuI,EAAM1O,UAAUC,OAAO,WAAW,CAE1C,CAAC,CACL,CAAC,EAnBD,IAsBMqR,EAAsB1R,SAASC,cAAc,iCAAiC,EACpF,GAAKyR,EAAsB,CACvB,IAAMC,EAAUvO,KAChBsO,EAAoBxP,iBAAiB,QAAS,WAC1CkB,KAAKT,QAAQ,4BAA4B,EAAEvC,UAAU4B,OAAO,QAAQ,EAEpE2P,EAAQlI,wBAAwB,EAChCrH,WAAW,KACP,IAAMkM,EAAmBtO,SAASC,cAAc,8BAA8B,EAC9EqO,EAAiBC,SAAS,CACtBC,IAAKF,EAAiBG,aACtBC,SAAU,QACd,CAAC,CACL,EAAG,CAAC,CACR,CAAC,CACL,CAEAtR,OAAO8E,iBAAiB,SAAUkB,KAAKwO,aAAaC,KAAKzO,IAAI,CAAC,EAC9DhG,OAAO8E,iBAAiB,SAAUkB,KAAK0O,aAAaD,KAAKzO,IAAI,CAAC,CAClE,CAEAiC,wBAAwB0M,EAAa5O,EAAO,SACxC,IAAM6O,EAAYhS,SAASM,eAAe,0CAA0C,EAC9E2R,EAAajS,SAASM,eAAe,mCAAmC,EACxE4R,EAAclS,SAASC,cAAc,sCAAsC,EAEtD,UAAvB,OAAO8R,GAA2C,OAAfE,GAAuC,OAAhBC,IAC1DD,EAAW/R,UAAYC,WAAW4R,CAAW,EAC7CG,EAAY9R,UAAUC,OAAO,QAAQ,EACrC4R,EAAW7R,UAAUC,OAAO,qCAAsC,mCAAmC,EACxF,WAAT8C,GACA6O,EAAU9R,UAAYC,WAAW,EAAE,EACnC+R,EAAY9R,UAAUiJ,IAAI,oCAAoC,EAC9D4I,EAAWxP,MAAM0P,MAAQ,YAEzBH,EAAU9R,UAAYC,WAAW,oBAAoB,EACrD+R,EAAY9R,UAAUiJ,IAAI,mCAAmC,EAC7D4I,EAAWxP,MAAM0P,MAAQ,OAGrC,CAEA1I,0BACI,IAAMP,EAAYlJ,SAASC,cAAc,qCAAqC,EACxEmS,EAASpS,SAASC,cAAc,sBAAsB,EACtDoS,EAAoBrS,SAASC,cAAc,+DAA+D,EAC1GqS,EAAsBtS,SAASC,cAAc,gDAAgD,EACnG,IAAWoS,GAAqBC,IAAyBpJ,EAAzD,CAKA,IAAMqJ,EAAUnV,OAAOmV,QACjBC,EAAiBpV,OAAOqV,YAExBC,EAAuBxJ,EAAUyJ,sBAAsB,EAAEnE,IAAM+D,EAE/DK,EAAeR,EAAOS,aAE5B/c,IAAI0Y,EAGAkE,EAAuBH,EAAU,EAEjC/D,EAAM,IACkCgE,EAAjCE,EAAuBH,GAMQC,EAAiBI,GADvDpE,EAAMkE,EAAuBH,MAGzB/D,EAAMgE,EAAiBI,EAAe,IAI9CR,EAAO3P,MAAM+L,IAASA,EAAH,KACnB4D,EAAO3P,MAAMqQ,OAAS,MA5BtB,CA6BJ,CAEAlB,eACItP,aAAac,KAAK2P,aAAa,EAC/B3P,KAAK2P,cAAgB3Q,WAAW,KAC5BgB,KAAKqG,wBAAwB,CACjC,EAAG,EAAE,CACT,CAEAqI,eACIxP,aAAac,KAAK4P,aAAa,EAC/B5P,KAAK4P,cAAgB5Q,WAAW,KAC5BgB,KAAKqG,wBAAwB,CACjC,EAAG,GAAG,CACV,CAOA0C,0BAA0BzB,GACtB,MAAO,CAAA,CACX,CAEAgB,iBAAiBlC,GACbyJ,EAAMvK,MAAMC,QAAQa,CAAQ,EAAInN,KAAKK,UAAU8M,CAAQ,EAAIoD,OAAOpD,CAAQ,EAE9E,MAAI,kBAAkBsH,KAAKmC,CAAG,EACnBA,EAEJ,EACX,CACA,CAEA,IAAIC,wBAA0B,KAC9B,IAAMC,cAAgB,CAAA,EAChBC,mBAAqB,IAQ3B,SAASC,cACL,IAAIC,qBACJ,IAAI1Q,uBAAuB,GAAI,MAAM,CACzC,CA8CA,SAASgN,oBACL,IAAIhN,uBAAuB,KAAM,cAAc,CACnD,CAOA,SAAS2Q,sBAAsBC,GAC3B,GAAKA,EAAL,CACA1d,IAAI0M,EAAKgR,EAAKC,WAAaC,KAAKC,aAAeH,EAAOA,EAAKI,cAC3D,KAAOpR,GAAI,CACP,GAAIA,EAAGpC,WAAaoC,EAAGpC,UAAUsG,SAAS,qBAAqB,EAC3D,MAAO,CAAA,EAEXlE,EAAKA,EAAGoR,aACZ,CAPuB,CAQvB,MAAO,CAAA,CACX,CAOA,SAAS/J,kBAAkBpN,EAAc0G,GACjC1G,GACA,IAAImG,uBAAuBnG,EAAc0G,CAAI,CAErD,CAOA,SAAS0Q,gBAAgBtd,GAChB4c,eACD7D,QAAQC,IAAIhZ,CAAO,CAE3B,CAEA,SAAS8Q,wBACL,IAAMyM,EAAW9T,SAAS+T,uBAAuB,oDAAoD,EACrG,GAAsB,EAAlBD,EAAS/X,OACT,IAAKjG,IAAIyU,EAAI,EAAGA,EAAIuJ,EAAS/X,OAASwO,CAAC,GACnCuJ,EAASvJ,GAAG9H,MAAMC,QAAU,OAGpC,IAAMsR,EAAyB,CAAC,2CAA4C,iDAC5E,IAAKle,IAAIyU,EAAI,EAAGA,EAAIyJ,EAAuBjY,OAASwO,CAAC,GAAI,CACrD,IAAM0J,EAAajU,SAAS+T,uBAAuBC,EAAuBzJ,EAAE,EAC5E,GAAwB,EAApB0J,EAAWlY,OACX,IAAKjG,IAAIyU,EAAI,EAAGA,EAAI0J,EAAWlY,OAASwO,CAAC,GACrC0J,EAAW1J,GAAG9H,MAAMC,QAAU,OAG1C,CACJ,CAEA,SAASyI,mBAAmB+I,EAAczb,GACtC,IAAM0C,EAAW+Y,EAAa/Y,SAASwC,OAAOvF,GACnCA,GAASK,QAAQmG,SAAS,IAAMnG,GAAQmG,SAAS,CAC3D,EACD,IAAMnD,EAAQyY,EAAazY,MAEvB0Y,EAAgC,EAAlBhZ,EAASY,OAAaZ,EAAS,GAAK,KAElDoE,EAAS,KAKExB,GAJXoW,GAAe1Y,GAAwB,EAAfA,EAAMM,SAC9BwD,EAAS9D,EAAMsB,KAAKoE,GAAKyL,OAAOzL,EAAE7J,OAAO,IAAMsV,OAAOuH,EAAY9c,MAAM,CAAC,GAGvD,IAClB8c,KACMC,EAAKxW,WAAWuW,EAAY9Y,WAAW,GACnCyC,KACVC,EAAOqW,EAAGrW,MAGdjI,IAAIue,EAAY/U,aAAaC,CAAM,EAC/B+U,EAAa5U,cAAcH,CAAM,EAErC,MAAO,CACH9G,OAAQA,EACRuG,uBAAwBqV,EACxBpV,eAAgBqV,EAChBhJ,gBAAiB6I,EAAcA,EAAY/Y,YAAc,kBACzDqQ,gBAAiB1N,EACjBzC,WAA8B,EAAlBH,EAASY,OAAaZ,EAAS,GAAGG,WAAa,WAC3DuN,cAAe1N,EACVgP,KAAK,CAACC,EAAGC,IACC,IAAInM,KAAKkM,EAAE/O,WAAW,EAAI,IAAI6C,KAAKmM,EAAEhP,WAAW,CAC1D,EACAb,IAAIpC,IACD,GAAM,CAAC0F,KAAAA,EAAMC,KAAAA,CAAI,EAAIH,WAAWxF,EAAQiD,WAAW,EACnDvF,IAAIyJ,EAAS,KAIb,MAAO,CACH+N,uBAAwBhO,aAHxBC,EADA9D,GAAwB,EAAfA,EAAMM,OACNN,EAAMsB,KAAKoE,GAAKyL,OAAOzL,EAAE7J,OAAO,IAAMsV,OAAOxU,EAAQf,MAAM,CAAC,EAGhCkI,CAAM,EAC3CgO,kBAAmB7N,cAAcH,CAAM,EACvCnE,YAAahD,EAAQgD,YACrBC,YAAayC,EACb2P,YAAa1P,EACbsP,cAAejV,EAAQf,QAAU,cACrC,CACJ,CAAC,CACT,CACJ,CAEA,SAAS6T,cAAcqJ,GACnBze,IAAI8V,EACAD,EACJ7V,IAAI+V,EACA0I,EAActV,gBAAkD,aAAhCsV,EAActV,eACxCsV,EAActV,eAAeU,KAAK,EAAE6U,OAAO,CAAC,EAAEC,YAAY,EAC1D,KACV3e,IAAIgW,EAAgB,sCAepB,OAd6C,OAAzCyI,EAAcvV,wBAA0D,OAAvB6M,IACjDD,EAAc,uFACdD,EAAiB,wCAEwB,OAAzC4I,EAAcvV,wBAA0D,OAAvB6M,IACjDD,EAAc,0jPACdD,EAAiB,uCACjBG,GAAiB,uCAEwB,OAAzCyI,EAAcvV,yBACd4M,2BAAwC2I,EAAcvV,4BACtD2M,EAAiB,uCACjBG,EAAgB,sCAEb,CACHF,YAAaA,EACbD,eAAgBA,EAChBE,mBAAoBA,EACpBC,cAAeA,CACnB,CACJ,CAOA,SAAS4I,iBAAiB1R,GACtBlN,IAEM6e,EAAkB,GAExB,IAAK7e,IAAIyU,EAAI,EAAGA,EAAIvH,EAAajH,OAAQwO,CAAC,GAAI,CAC1C,IAAMqK,EAAqB5R,EAAauH,GAClCsK,EAAW7c,aAAaC,QAAQ,iBAAiB,EAEnD2c,EAAmBnc,QACnBmc,EAAmBla,gBACnBka,EAAmB9Z,oBAAoB8D,SAAS,IAAMiW,EAASjW,SAAS,GAE/DkW,uBAAuBF,EAAmBnc,OAAQmc,EAAmBla,cAAc,GAExFia,EAAgB/S,KAAKgT,EAAmBnc,OAAOmG,SAAS,CAAC,CAGrE,CAEA,OAAkC,IAA3B+V,EAAgB5Y,QAAuB4Y,CAClD,CAMAxf,eAAesQ,gCAAgCzC,EAAc/J,GACzD,IAAM8b,EAAiBL,iBAAiB1R,CAAY,EACpDlN,IAAIoB,EAAS,CAAA,EACb,GAAI,CAAC6d,EACD,MAAO,CAAA,EAEX,IAAKjf,IAAIyU,EAAI,EAAGA,EAAIwK,EAAehZ,OAAQwO,CAAC,GAAI,CAC5C,IAIcyK,EAJRC,EAAgBF,EAAexK,GACR,UAAzB,OAAO0K,IACDC,EAAmB/e,MAAM0G,oBAAoB5D,EAAQ,CAACgc,EAAc,GACtD9Z,UAGkB5F,KAAAA,KAF5Byf,EAAcE,EAAgB/Z,SAAS,IAE7BkS,eACZ2H,EAAY3H,gBAAkBrV,aAAaC,QAAQ,iBAAiB,GAClC,cAAlC+c,EAAYzH,oBAEZ4H,gCAAgCF,CAAa,EAC7C/d,EAAS,CAAA,EAIzB,CACA,OAAOA,CACX,CAOA,SAASke,mBAAmBlM,GACxB,MAAO,CAAA,CACX,CAQA,SAAS/I,WAAWkV,EAAMC,EAAU,CAAA,GAChCxf,IAAIyf,EAAc,CACdnL,EAAG,CAAA,EACHC,EAAG,CAAA,EACHE,EAAG,CAAA,EACHiL,OAAQ,CAAA,EACRC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,EAAG,CAAA,EACHpJ,EAAG,CAAA,EACHqJ,GAAI,CAAA,EACJC,KAAM,CAAA,EACNC,WAAY,CAAA,EAQZA,WAAY,CAAA,EAPZC,IAAK,CAAA,EAQLA,IAAK,CAAA,EAPLC,IAAK,CAAA,EACLC,IAAK,CAAA,EACLrH,MAAO,CAAA,EACPsH,MAAO,CAAA,EACPhI,SAAU,CAAA,EACViI,OAAQ,CAAA,EAGRC,QAAS,CAAA,EACTC,QAAS,CAAA,CACb,EACIC,EAAe,CACfpM,EAAG,CAAC,OAAQ,QAAS,SAAU,MAAO,QAAS,SAC/C2L,KAAM,CAAC,QAAS,QAAS,MACzBF,EAAG,CAAC,QAAS,SACbK,IAAK,CAAC,QAAS,QAAS,KAAM,iBAAkB,gBAChDC,IAAK,CAAC,MAAO,MAAO,QAAS,QAAS,QAAS,QAAS,UACxDrH,MAAO,CAAC,OAAQ,QAAS,QAAS,KAAM,WAAY,SAAU,SAC9DsH,MAAO,CAAC,MAAO,QAAS,SACxBhI,SAAU,CAAC,QAAS,KAAM,QAAS,OAAQ,OAAQ,WAAY,WAAY,QAC3EiI,OAAQ,CAAC,OAAQ,QAAS,QAAS,MACnCC,QAAS,CAAC,QAAS,QAAS,QAC5BC,QAAS,CAAC,QAAS,QACvB,EAEIjB,GAAgC,gBAArBA,EAAQlF,WACnBmF,EAAc,CAAE,GAAGA,EAAaO,GAAI,CAAA,CAAM,GAI9C,IAAMW,GADS,IAAIC,WACAC,gBAAgBtB,EAAM,WAAW,EAwDpD,MADA,CAAC,GAAGoB,EAAIpgB,KAAKugB,YAAY9G,QAtDzB,SAAS+G,EAAMrD,GACX,GAAIA,EAAKC,WAAaC,KAAKC,aAAc,CACrC,IAAMmD,EAAMtD,EAAKuD,QAAQC,YAAY,EAErC,GAAI1B,EAAS,CAGL,IAGU2B,EAkBAlR,EACAmR,EACAD,EAzBd,GAAI1B,EAAYuB,IAEA,QAARA,GAAsC,+BAArBxB,EAAQlF,UAA6CkF,EAAQ5E,UAc9E,OAbM3K,EAAMyN,EAAKzD,aAAa,KAAK,GAAK,GAClCmH,EAAM1D,EAAKzD,aAAa,KAAK,GAAK,WAClCkH,EAAOR,EAAIjP,cAAc,GAAG,GAC7BlK,KAAOyI,EACZkR,EAAKE,OAAS,SACdF,EAAKxP,UAAY,gCACX0O,EAAMM,EAAIjP,cAAc,KAAK,GAC/BzB,IAAMA,EACVoQ,EAAIe,IAAMA,EACVf,EAAI1O,UAAY,8CAChBwP,EAAKjO,YAAYmN,CAAG,EACpB3C,EAAK4D,WAAWC,aAAaJ,EAAMzD,CAAI,EAJvC2C,KAKA3C,EAAKnT,OAAO,EAKpB,GAAI,CAACkV,EAAYuB,GAYb,MAVY,QAARA,GAAsC,gBAArBxB,EAAQlF,UAA8BkF,EAAQ5E,YACzD3K,EAAMyN,EAAKzD,aAAa,KAAK,GAAK,GAClCmH,EAAM1D,EAAKzD,aAAa,KAAK,GAAK,WAClCkH,EAAOR,EAAIjP,cAAc,GAAG,GAC7BlK,KAAOyI,EACZkR,EAAKE,OAAS,SACdF,EAAKK,YAAcJ,EACnB1D,EAAK4D,WAAWC,aAAaJ,EAAMzD,CAAI,GAP3C,KASAA,EAAKnT,OAAO,CAGpB,CAGA,CAAC,GAAGmT,EAAK+D,YAAYzH,QAAQ0H,IACzB,IAAMC,EAAWD,EAAKtf,KAAK8e,YAAY,EAClCR,EAAaM,IAAM7Y,SAASwZ,CAAQ,GACrCA,CAAAA,EAASC,WAAW,IAAI,GACxBF,CAAAA,EAAKjR,MAAMyQ,YAAY,EAAE/Y,SAAS,aAAa,GAC/CuV,EAAK7L,gBAAgB6P,EAAKtf,IAAI,CAEtC,CAAC,CACL,CAEA,CAAC,GAAGsb,EAAKoD,YAAY9G,QAAQ+G,CAAK,CACtC,CACsC,EAC/BJ,EAAIpgB,KAAKqR,SACpB,CAtX4B,YAAxB1H,SAAS2X,WACT3X,SAASkC,iBAAiB,gBAAiBmR,WAAW,EAEtDrT,SAASkC,iBAAiB,mBAAoBmR,WAAW,EAQ7DrT,SAASkC,iBAAiB,kBAAmB,SAAS0G,GAGlD,IAKMgP,EALFhP,EAAEuO,SAAWnX,WAIX6X,EAA2B,CAAC,CAAE7X,SAAS+T,uBAAuB,aAAa,EAAE,IAC7E6D,EAAM5X,SAASmJ,aAAa,IAEF,KAAnByO,EAAIhZ,SAAS,GAAaiZ,CAAAA,GAKnC3E,yBACA5Q,aAAa4Q,uBAAuB,EAGxCA,wBAA0B9Q,WAAW,KACjC,IAMQ0V,EAIErb,EAVJyM,EAAY9L,OAAO+L,aAAa,EAEf,UAAnBD,EAAU/F,OAGN4U,EAAa7O,EAAU6O,WACvBD,EAAY5O,EAAU4O,UACtBvE,sBAAsBwE,CAAU,GAAKxE,sBAAsBuE,CAAS,IAGlErb,EAAe8M,uBAAuBL,CAAS,IAIjDW,kBAAkBpN,EAAc,aAAa,EAGzD,EAAG2W,kBAAkB,GA1BjB,IAAIxQ,uBAAuB,GAAI,MAAM,EA2B7C,CAAC,EA8UD,IAAMoV,4BAA8B,OAC9BC,2BAA6B,QAC7BC,+BAAiC,UAOvC,SAASC,wBAAwBjP,GAC7B,IAAMkP,EAAQlP,EAAUmP,WAAW,CAAC,EAC9BC,EAAiBF,EAAMG,wBAG7B,OAAIC,wBAAwBtP,CAAS,EAC1B+O,2BAIPK,EAAe7E,WAAaC,KAAKC,cACE,EAAnC2E,EAAe1B,WAAW7a,QACE,KAA5Bqc,EAAMxZ,SAAS,EAAEe,KAAK,GACtByY,EAAMK,iBAAmBL,EAAMM,cAC/BN,EAAMK,eAAehF,WAAaC,KAAKC,aAChCuE,gCAILS,EAAkD,EAAjCP,EAAMxZ,SAAS,EAAEe,KAAK,EAAE5D,OACzC6c,EAAaN,EAAe7E,WAAaC,KAAKmF,UAC9CC,EAAcV,EAAMW,UAEtBJ,CAAAA,GAAmBC,CAAAA,GAAeE,EAI/B,KAHId,4BAIf,CAOA,SAASzO,uBAAuBL,GAG5B,GAAI,CAACA,EAA0F,OAA9E2K,gBAAgB,2DAA2D,EAAU,KAEtG,GAA6B,IAAzB3K,EAAU8P,WAA8F,OAA1EnF,gBAAgB,uDAAuD,EAAU,KAEnH,GAA2B,EAAvB3K,EAAU8P,WAAiG,OAA/EnF,gBAAgB,4DAA4D,EAAU,KAEtH,IAAMuE,EAAQlP,EAAUmP,WAAW,CAAC,EAEpC,GAAID,EAAMK,iBAAmBL,EAAMM,aAA2G,OAA3F7E,gBAAgB,wEAAwE,EAAU,KAGrJ,IAAMoF,EAAgBd,wBAAwBjP,CAAS,EAGvD,GAAI,CAAC+P,EAAsG,OAArFpF,gBAAgB,kEAAkE,EAAU,KAGlH/d,IAAIyG,EAAe,GACf2c,EAAsB,EACtBC,EAAoB,EACpB3P,EAAW,GACf1T,IAEMsjB,EAAahB,EAAMG,wBAEzB,OAAQU,GACJ,KAAKjB,4BACD,GAAuC,IAAnCI,EAAMxZ,SAAS,EAAEe,KAAK,EAAE5D,OAExB,OADA8X,gBAAgB,4DAA4D,EACrE,KAEX,IAAMwF,EAAoBD,EAAW3F,WAAaC,KAAKC,aAAeyF,EAAaA,EAAWxF,cAC9FrX,EAAe6b,EAAMxZ,SAAS,EAC9Bsa,EAAsBd,EAAMkB,YAC5BH,EAAoBf,EAAMmB,UACG,IAAxBL,GAA6B3c,EAAaR,OAASod,IACpDA,EAAoB5c,EAAaR,QAErCyN,EAAWgQ,yBAAyBH,CAAiB,EACrD,MAEJ,KAAKpB,2BACD,IAAMwB,EAAarB,EAAMK,eACnBiB,EAAgBlB,wBAAwBtP,CAAS,EACvD3M,YAAyBmd,EAAcxC,KAA0B,oBACjE1N,EAAWgQ,yBAAyBE,CAAa,EAEjDR,EAAsBxQ,MAAMiR,KAAKF,EAAWrC,WAAWwC,QAAQ,EAAEC,QAAQJ,CAAU,EACnFN,EAAoBD,EAAsB,EAC1C,MAEJ,KAAKhB,+BACKhZ,EAAUka,EAAW3F,WAAaC,KAAKC,aAAeyF,EAAaA,EAAWxF,cACpF,GAAI1U,EAAQ0X,WAAW7a,QAAU,EAE7B,OADA8X,gBAAgB,kEAAkE,EAC3E,KAEXtX,EAAe2C,EAAQoY,aAAe,GACtC9N,EAAWgQ,yBAAyBta,CAAO,EAE3Cga,EAAsBxQ,MAAMiR,KAAKza,EAAQkY,WAAWwC,QAAQ,EAAEC,QAAQ3a,CAAO,EAC7Eia,EAAoBD,EAAsB,CAElD,CAGA,IAAMvf,EAAUyD,OAAOC,SAASC,KAEhC,MAAO,CACH4b,oBAAAA,EACAC,kBAAAA,EACA5c,aAAcA,EAAaoD,KAAK,EAChChG,QAAAA,EACA6P,SAAAA,EACAyP,cAAAA,EACAa,UAA4B7B,2BAtDjB,GAuDf,CACJ,CAOA,SAAS7L,yBAAyBpC,EAAsB+P,GAEpD,GAAoC,IAAhC/P,EAAqBjO,OAAzB,CAEA,IAAMie,EAAc,IAAIC,IAGxBjQ,EAAqB8F,QAAQoK,IAEzB,IAWMhb,EAXDgb,GAAM1Q,UAAad,MAAMC,QAAQuR,GAAM1Q,QAAQ,EAM/CpG,KAAK+W,uBAAuBD,EAAK1Q,QAAQ,GAKxCtK,EAAUkb,4BAA4BF,EAAK1Q,QAAQ,GAMlD0Q,EAAKjB,cASRiB,EAAKjB,eACL,CAAC,CACGjB,4BACAC,2BACAC,gCACFja,SAASic,EAAKjB,aAAa,EAE7BpF,gBAAgB,2BAA6BqG,EAAKjB,aAAa,GAI9De,EAAYK,IAAInb,CAAO,GACxB8a,EAAYM,IAAIpb,EAAS,EAAE,EAE/B8a,EAAYlV,IAAI5F,CAAO,EAAE0C,KAAKsY,CAAI,GApB9BrG,gBAAgB,iCAAiC,EAPjDA,gBAAgB,+BAAiCqG,EAAK1Q,QAAQ,EAN9DqK,gBAAgB,4BAA8BqG,EAAK1Q,QAAQ,EAN3DqK,gBAAgB,8CAAgDqG,CAAI,CAwC5E,CAAC,EAEDF,EAAYlK,QAAQ,CAACyK,EAAOrb,KACxB,IAAM+Z,EAAgBsB,EAAM,GAAGtB,cAG/B,OAAQA,GACJ,IAAK,QACD7V,KAAKoX,6BAA6Btb,CAAO,EACzC,MAEJ,IAAK,UACDkE,KAAKqX,8BAA8Bvb,CAAO,EAC1C,MAEJ,IAAK,OACDkE,KAAKsX,8BAA8Bxb,EAASqb,EAAOR,CAAc,EACjE,MAEJ,QACIlG,gBAAgB,2BAA6BoF,CAAa,CAClE,CACJ,CAAC,CAtE4C,CAuEjD,CAMA,SAASuB,6BAA6Btb,GACV,QAApBA,EAAQ6X,QACRlD,gBAAgB,kDAAoD3U,EAAQ6X,OAAO,EAGvF7X,EAAQkB,UAAUiJ,IAAI,qCAAqC,CAC/D,CAMA,SAASoR,8BAA8Bvb,GACnCA,EAAQkB,UAAUiJ,IAAI,uCAAuC,CACjE,CAQA,SAASqR,8BAA8Bxb,EAASqb,EAAMR,GAClDjkB,IAAI6kB,EAAmB,GAevB,IAAMC;;;uCAbFD,EADAJ,EAAM,GAAG5P,QACU,4BAEA;2IAOgH4P,EAAM,GAAG9hB;;yCAO5IoiB,EAAO3b,EAAQoY,YACnB,IAAMwD,EAAmBP,EAAM,GAAGhe,aAGlC,GAAOue,EAAP,CAKA,IAAMC,EAAU,GAiBhB,GAdAR,EAAMzK,QAAQoK,IAEV,IAAMc,EAAWC,SAASf,EAAKhB,mBAAmB,GAAK,EACjDgC,EAASD,SAASf,EAAKf,iBAAiB,GAAK,EAE/C6B,EAAW,GAAKE,EAASL,EAAK9e,QAAqBmf,EAAXF,EACxCnH,gBAAgB,2BAA6BqG,CAAI,GAIrDa,EAAQnZ,KAAK,CAAEuZ,SAAUH,EAAU7X,KAAM,OAAQ,CAAC,EAClD4X,EAAQnZ,KAAK,CAAEuZ,SAAUD,EAAQ/X,KAAM,KAAM,CAAC,EAClD,CAAC,EAEsB,IAAnB4X,EAAQhf,OAOZ,GAJAgf,EAAQ5Q,KAAK,CAACC,EAAGC,IAAMA,EAAE8Q,SAAW/Q,EAAE+Q,QAAQ,EAIzCN,EAAKO,MAAML,EAAQ,GAAGI,SAAUJ,EAAQ,GAAGI,QAAQ,IAAML,EAC1DjH,gBAAgB,4DAA4D,MADhF,CAKA/d,IAAIoB,EAAS2jB,EACbE,EAAQjL,QAAQuL,IACZ,IAAMC,EAA6B,UAAhBD,EAAOlY,KACpByX,EA3CoB,UA8C1B1jB,EAASA,EAAOkkB,MAAM,EAAGC,EAAOF,QAAQ,EAAIG,EAAapkB,EAAOkkB,MAAMC,EAAOF,QAAQ,CACzF,CAAC,EAGD,IACIjc,EAAQwI,UAAYvH,WAAWjJ,CAAM,EACrC8I,SAAS6P,iBAAiB,+BAA+B,EAAEC,QAAQmH,IAC/DA,EAAK/U,iBAAiB,QAAS,IAE3B0G,EAAEiG,eAAe,EAEX0M,EADYtE,EAAKxP,UAAUhG,MAAM,GAAG,EAChB1E,KAAKye,GAAOA,EAAIvd,SAAS,YAAY,CAAC,EAChEnI,IAAI2C,EAAS,MAETA,EADA8iB,EACSA,EAAQ9Z,MAAM,YAAY,EAAE,GAErChJ,KACAshB,EAAejd,oBAAsBrE,EACrCshB,EAAe/J,YAAY,EAEnC,CAAC,CACL,CAAC,CAGL,CAFE,MAAO/Z,GACL4d,gBAAgB,mCAAqC5d,CAAK,CAC9D,CAhCA,CA7BA,MAFI4d,gBAAgB,+BAA+B,CAgEvD,CAOA,SAASvK,wBAAwBmS,GACvBjI,EAAO4G,4BAA4BqB,CAAI,EAC7C,MAAA,EAAIjI,CAAAA,GAAQA,CAAAA,EAAKkI,iBACblI,EAAKkI,eAAe,CAAEhN,SAAU,SAAUiN,MAAO,QAAS,CAAC,EACpD,GAGf,CAEA,SAAS1S,0BACL,IACM2S,EAAQ5b,SAAS6P,iBAAiB,qCAA4B,EACpE,IAAMgM,EAAkB,IAAIC,IAkBtBC,GAhBNH,EAAM9L,QAAQiG,IACV,IAAMiG,EAASjG,EAAKqB,WAEd6E,GADNJ,EAAgBxS,IAAI2S,CAAM,EACVjG,EAAK9V,cAAc,6CAA6C,GAIhF,IAHIgc,GAASA,EAAQ5b,OAAO,EAGrB0V,EAAKmG,YACRF,EAAO3E,aAAatB,EAAKmG,WAAYnG,CAAI,EAE7CiG,EAAOG,YAAYpG,CAAI,CAC3B,CAAC,EAGD8F,EAAgB/L,QAAQkM,GAAUA,EAAOI,UAAU,CAAC,EAElB,yCAK5BC,GAJWrc,SAAS6P,iBAAiB,IAAIkM,CAA2B,EACjEjM,QAAQ5Q,IACbA,EAAQkB,UAAUC,OAAO0b,CAAyB,CACtD,CAAC,EAC+B,uCACjB/b,SAAS6P,iBAAiB,IAAIwM,CAAyB,EAC/DvM,QAAQ5Q,IACXA,EAAQkB,UAAUC,OAAOgc,CAAuB,CACpD,CAAC,CACL,CAOA,SAASlC,uBAAuB3Q,GAC5B,MAAKd,CAAAA,CAAAA,MAAMC,QAAQa,CAAQ,GACH,IAApBA,EAASzN,QAENyN,EAAS8S,MAAMC,GACXnP,OAAOoP,UAAUD,CAAK,GAAc,GAATA,GAAcA,EAAQ,GAC3D,CACL,CAOA,SAAS/D,wBAAwBtP,GAE7B,GAAKA,GAAsC,IAAzBA,EAAU8P,YAAoB9P,CAAAA,EAAU4P,YAA1D,CAIA,IAAMV,EAAQlP,EAAUmP,WAAW,CAAC,EAGpC,GAAID,EAAMK,iBAAmBL,EAAMM,cAC/BN,EAAMK,eAAehF,WAAaC,KAAKC,cACN,QAAjCyE,EAAMK,eAAe1B,QACrB,OAAOqB,EAAMK,eAiBbgE,EAbWzc,SAAS0c,iBACpBtE,EAAMG,wBACNoE,WAAWC,aACX,CACIC,WAAY,SAASrJ,GACjB,MAAwB,QAAjBA,EAAKuD,SACZ+F,wBAAwBtJ,EAAM4E,CAAK,EAC/BuE,WAAWI,cACXJ,WAAWK,aACnB,CACJ,CACJ,EAEqBC,SAAS,EAC9B,GAAIR,EACA,OAAOA,EAIX,IAgBWvd,EAhBLge,EAAeC,0BAA0B/E,EAAMK,cAAc,EAC7D2E,EAAaD,0BAA0B/E,EAAMM,YAAY,EAG/D,GAAIwE,GAAyC,QAAzBA,EAAanG,SAC7BsG,kCAAkCH,EAAc9E,CAAK,EACrD,OAAO8E,EAGX,GAAIE,GAAqC,QAAvBA,EAAWrG,SACzBsG,kCAAkCD,EAAYhF,CAAK,EACnD,OAAOgF,EAKX,IAAWle,KADYoe,0BAA0BlF,CAAK,EAElD,GAAwB,QAApBlZ,EAAQ6X,QACR,OAAO7X,CAjDf,CAqDA,OAAO,IACX,CAEA,SAAS4d,wBAAwB5d,EAASkZ,GACtC,IAAMmF,EAAevd,SAASwd,YAAY,EAE1C,OADAD,EAAaE,WAAWve,CAAO,EACxBkZ,EAAMsF,sBAAsBC,MAAMC,eAAgBL,CAAY,GAAK,GACP,GAA/DnF,EAAMsF,sBAAsBC,MAAME,WAAYN,CAAY,CAClE,CAEA,SAASF,kCAAkCne,EAASkZ,GAC1C0F,EAAc5e,EAAQyT,sBAAsB,EAC5CoL,EAAY3F,EAAMzF,sBAAsB,EAG9C,MAAO,EAAEmL,EAAYE,MAAQD,EAAUE,MACnCH,EAAYG,KAAOF,EAAUC,OAC7BF,EAAYhL,OAASiL,EAAUvP,KAC/BsP,EAAYtP,IAAMuP,EAAUjL,OACpC,CAEA,SAASqK,0BAA0B3J,GAC/B,OAAOA,EAAKC,WAAaC,KAAKC,aAAeH,EAAOA,EAAKI,aAC7D,CAOA,SAAS0J,0BAA0BlF,GAC/B,IAAM8F,EAAW,GACXpU,EAAYsO,EAAMG,wBAGlB4F,EAAkBrU,EAAUsU,uBAC5BC,EAAcvU,EAAUwU,mBAU9B,GARIH,GACAD,EAAStc,KAAKuc,CAAe,EAE7BE,GACAH,EAAStc,KAAKyc,CAAW,EAIzBvU,EAAU2J,WAAaC,KAAKC,aAAc,CAC1C,IAAMiG,EAAW9P,EAAU8P,SAC3B,IAAK9jB,IAAIyU,EAAI,EAAGA,EAAIqP,EAAS7d,OAAQwO,CAAC,GAC9B8S,kCAAkCzD,EAASrP,GAAI6N,CAAK,GACpD8F,EAAStc,KAAKgY,EAASrP,EAAE,CAGrC,CAEA,OAAO2T,CACX,CAQA,SAAS1E,yBAAyBhG,GAE9B,IADA1d,IAAI2lB,EAAO,GACJjI,GAAM,CACT1d,IAAIymB,EAAQ,EACRgC,EAAU/K,EAAKgL,gBACnB,KAAOD,GACsB,IAArBA,EAAQ9K,UACR8I,CAAK,GAETgC,EAAUA,EAAQC,gBAEtB/C,EAAKgD,QAAQlC,CAAK,EAClB/I,EAAOA,EAAK4D,UAChB,CAKA,OAFAqE,EAAKiD,MAAM,EAEJjD,CACX,CAQA,SAASrB,4BAA4BqB,GAEjC,GAAK,CAAEA,EACH,OAAO,KAGX3lB,IAAI0d,EAAOxT,SACX,IAAKlK,IAAIyU,EAAI,EAAGA,EAAIkR,EAAK1f,OAAQwO,CAAC,GAE9B,GAAK,EADLiJ,EAAOA,EAAKoG,SAAS6B,EAAKlR,KAEtB,OAAO,KAGf,OAAOiJ,CACX,CAEA1d,IAAI6oB,yzwBAKJ,SAASxW,2BACL,MAA4D,MAArDnQ,aAAaC,QAAQ,0BAA0B,CAC1D,CAMA,SAAS0N,0BACL,OAA4D,OAArD3N,aAAaC,QAAQ,0BAA0B,CAC1D,CAMA,SAAS+M,yBAAyB4Z,GAC9B5mB,aAAaqC,QAAQ,2BAA4BukB,EAAU,IAAM,GAAG,CACxE,CAMA,SAAS1W,0BACL,OAAmD,OAA5ClQ,aAAaC,QAAQ,iBAAiB,CACjD,CAMA,SAASyN,2BAA2BnL,GAChC,GAAKA,GAAUmO,MAAMC,QAAQpO,CAAK,EAAlC,CAIAzE,IAAI+oB,EAAc,GAClB,IACIA,EAAcxiB,KAAKC,MAAMtE,aAAaC,QAAQ,sBAAsB,GAAK,IAAI,CAGjF,CAFE,MAAOhC,GACL4oB,EAAc,EAClB,CAEAtkB,EAAMuV,QAAQrV,IACNA,EAAKhC,QAAUgC,EAAKC,iBACpBmkB,EAAYpkB,EAAKhC,QAAU,CACvBA,OAAQgC,EAAKhC,OACbiC,eAAgBD,EAAKC,cACzB,EAER,CAAC,EAED1C,aAAaqC,QAAQ,uBAAwBgC,KAAKK,UAAUmiB,CAAW,CAAC,CAlBxE,CAmBJ,CAEA,SAAS5jB,sBAAsBV,GACtBA,GAAUmO,MAAMC,QAAQpO,CAAK,IAI5BukB,EAAQvkB,EAAMoD,OAAOlD,GAChBA,EAAKlC,QACf,GAAGwD,OAEJ/D,aAAaqC,QAAQ,sBAAuB,GAAGykB,CAAO,EAC1D,CAQA,SAAShK,uBAAuBrc,EAAQsmB,GACpC,GAAI,CAACtmB,GAAU,CAACsmB,EACZ,OAAO,KAGXjpB,IAAI+oB,EAAc,GAClB,IACIA,EAAcxiB,KAAKC,MAAMtE,aAAaC,QAAQ,sBAAsB,GAAK,IAAI,CAGjF,CAFE,MAAOhC,GACL4oB,EAAc,EAClB,CACMG,EAAaH,EAAYpmB,GAE/B,MAAKumB,CAAAA,CAAAA,GAIgB,IAAI9gB,KAAK8gB,EAAWtkB,cAAc,EACjC,IAAIwD,KAAK6gB,CAAiB,CAEpD,CAMA,SAAS5J,gCAAgC1c,GACrC,GAAKA,EAAL,CAIA3C,IAAImpB,EAAe,GACnB,IACIA,EAAe5iB,KAAKC,MAAMtE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACLgpB,EAAe,EACnB,CAEKA,EAAahhB,SAASxF,CAAM,GAC7BwmB,EAAard,KAAKnJ,CAAM,EAG5BT,aAAaqC,QAAQ,yBAA0BgC,KAAKK,UAAUuiB,CAAY,CAAC,CAb3E,CAcJ,CAMA,SAAS/R,mCAAmCzU,GACxC,GAAKA,EAAL,CAIA3C,IAAImpB,EAAe,GACnB,IACIA,EAAe5iB,KAAKC,MAAMtE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACLgpB,EAAe,EACnB,CACAA,EAAeA,EAAathB,OAAOuhB,GAAMA,IAAOzmB,CAAM,EACtDT,aAAaqC,QAAQ,yBAA0BgC,KAAKK,UAAUuiB,CAAY,CAAC,CAT3E,CAUJ,CAMA,SAASzZ,+BACL1P,IAAImpB,EAAe,GACnB,IACIA,EAAe5iB,KAAKC,MAAMtE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACLgpB,EAAe,EACnB,CAEA,OAA6B,EAAtBA,EAAaljB,MACxB,CAOA,SAASmQ,oCAAoCzT,GACzC,GAAI,CAACA,EACD,MAAO,CAAA,EAGX3C,IAAImpB,EAAe,GACnB,IACIA,EAAe5iB,KAAKC,MAAMtE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACLgpB,EAAe,EACnB,CAEA,OAAOA,EAAahhB,SAASxF,EAAOmG,SAAS,CAAC,CAClD,OAMM2F,aAKFrB,YAAYic,GAER/b,KAAKgc,MAAQ,GAGbhc,KAAKic,YAAc,QAGnBjc,KAAKkc,aAAe,SAGpBlc,KAAKmc,SAAW,EAGhBnc,KAAKoc,aAAe,CAAC,aAAc,YAAa,YAAa,kBAAmB,aAAc,sBAG9Fpc,KAAK+b,kBAAoBA,EAGzB/b,KAAKqc,WAAa,CAAC,QAAS,KAAM,KAAM,KAC5C,CAMApc,OACID,KAAKsc,mBAAmB,EACxBtc,KAAKuc,qBAAqB,CAC9B,CAMAD,qBAEItc,KAAKwc,UAAY5f,SAASM,eAAe,qDAAqD,EAG9F8C,KAAKyc,SAAW7f,SAASM,eAAe,6CAA6C,EAErF8C,KAAK0c,gBAAkB9f,SAASM,eAAe,2CAA2C,EAG1F8C,KAAKxM,aAAeoJ,SAASM,eAAe,yCAAyC,EAEhF8C,KAAKwc,WAAcxc,KAAKyc,UAAazc,KAAKxM,cAAgBwM,CAAAA,KAAK0c,iBAChExQ,QAAQyQ,KAAK,kCAAkC,CAEvD,CAMAJ,uBACQvc,KAAKwc,WACLxc,KAAKwc,UAAU1d,iBAAiB,SAAU,GAAOkB,KAAK4c,sBAAsBpX,CAAC,CAAC,CAEtF,CAOA+G,oBAAoBzQ,GAChBA,EAAQgD,iBAAiB,QAAS,IAC9B0G,EAAEiG,eAAe,EACbzL,KAAKwc,WACLxc,KAAKwc,UAAUK,MAAM,CAE7B,CAAC,CACL,CAOAD,sBAAsBE,GAClB9c,KAAK+c,WAAW,EAEhB,IAAMC,EAAgB1X,MAAMiR,KAAKuG,EAAM/I,OAAOiI,KAAK,EAC/Chc,KAAKgc,MAAMrjB,OAASqkB,EAAcrkB,OAASqH,KAAKmc,SAChDnc,KAAKgM,qBAAqBhM,KAAKmc,iCAAiC,GAGjDa,EAAcziB,OAAOtE,GAAQ+J,KAAKid,aAAahnB,CAAI,CAAC,EAE5DyW,QAAQzW,GAAQ+J,KAAKkd,QAAQjnB,CAAI,CAAC,EAG7C6mB,EAAM/I,OAAO5Q,MAAQ,GAGrBnD,KAAK0c,gBAAgBrd,MAAMC,QAAU,QACzC,CAOA2d,aAAahnB,GAET,OAAIA,EAAKknB,KAAOnd,KAAKic,aACjBjc,KAAKgM,mBAAmB/V,EAAKnB,qCAAqCkL,KAAKod,eAAepd,KAAKic,WAAW,CAAG,EAClG,CAAA,GAIOjc,KAAKqd,aAAa,EAAIpnB,EAAKknB,KAC7Bnd,KAAKkc,cACjBlc,KAAKgM,UAAU,uCAAuChM,KAAKod,eAAepd,KAAKkc,YAAY,CAAG,EACvF,CAAA,GAIX,EAA+B,EAA3Blc,KAAKoc,aAAazjB,QAAeqH,CAAAA,KAAKoc,aAAavhB,SAAS5E,EAAK8J,IAAI,IACrEC,KAAKgM,wBAAwB/V,EAAK8J,cAAc9J,EAAKnB,yBAAyB,EACvE,GAIf,CAMAuoB,eACI,OAAOrd,KAAKgc,MAAMsB,OAAO,CAACC,EAAK3nB,IAAa2nB,EAAM3nB,EAASK,KAAKknB,KAAM,CAAC,CAC3E,CAOAD,QAAQjnB,GACEunB,EAAa,CACf1B,GAAI9b,KAAKyd,eAAe,EACxBxnB,KAAMA,CACV,EAEA+J,KAAKgc,MAAMxd,KAAKgf,CAAU,EAC1Bxd,KAAK0d,eAAe,CACxB,CAOAD,iBACI,OAAO3iB,KAAK6iB,IAAI,EAAIC,KAAKC,OAAO,EAAEriB,SAAS,EAAE,EAAEsiB,OAAO,EAAG,CAAC,CAC9D,CAOAC,WAAWC,GACPhe,KAAKgc,MAAQhc,KAAKgc,MAAMzhB,OAAO0jB,GAAKA,EAAEnC,KAAOkC,CAAM,EACnDhe,KAAK0d,eAAe,EACpB1d,KAAK+c,WAAW,CACpB,CAMAW,iBACI,IAOMQ,EAPDle,KAAKyc,WAEgB,IAAtBzc,KAAKgc,MAAMrjB,OACXqH,KAAKyc,SAASnY,UAAYvH,WAAW,4EAA4E,GAI/GmhB,EAAYle,KAAKgc,MAAM5kB,IAAIxB,GAAYoK,KAAKme,eAAevoB,CAAQ,CAAC,EAC1EoK,KAAKyc,SAASnY,UAAYvH,WAAW,EAAE,EACvCmhB,EAAUxR,QAAQ9S,GAAQoG,KAAKyc,SAAS7W,YAAYhM,CAAI,CAAC,GAC7D,CASAukB,eAAevoB,GACX,GAAM,CAAEK,KAAAA,EAAM6lB,GAAAA,CAAG,EAAIlmB,EACfwoB,EAAWxhB,SAASwH,cAAc,KAAK,EAgB7C,OAfAga,EAAS/Z,UAAY,8CAErB+Z,EAAS9Z,UAAYvH;;;+EAGkDiD,KAAK+b,kBAAkBvS,OAAOvT,EAAKnB,IAAI,CAAC;+EACxCkL,KAAKod,eAAennB,EAAKknB,IAAI;;;uGAGLrB;SAC9F,EAEiBsC,EAASvhB,cAAc,+CAA+C,EAC9EiC,iBAAiB,QAAS,IAAMkB,KAAK+d,WAAWjC,CAAE,CAAC,EAEtDsC,CACX,CAOAhB,eAAeiB,GACX,IAGMlX,EAHN,OAAc,IAAVkX,EAAoB,WAGlBlX,EAAIyW,KAAKU,MAAMV,KAAKzR,IAAIkS,CAAK,EAAIT,KAAKzR,IADlC,IACuC,CAAC,EAE3CoS,YAAYF,EAAQT,KAAKY,IAHtB,KAG6BrX,CAAC,GAAGsX,QAAQ,CAAC,CAAC,EAAI,IAAMze,KAAKqc,WAAWlV,GACnF,CAOA6E,UAAU7Y,GACF6M,KAAKxM,eACLwM,KAAKxM,aAAa0gB,YAAc/gB,EAChC6M,KAAKxM,aAAa6L,MAAMC,QAAU,QAE1C,CAMAyd,aACQ/c,KAAKxM,eACLwM,KAAKxM,aAAa0gB,YAAc,GAChClU,KAAKxM,aAAa6L,MAAMC,QAAU,OAE1C,CAMAuM,WACI,OAA2B,EAApB7L,KAAKgc,MAAMrjB,MACtB,CAMA+lB,aACI1e,KAAKgc,MAAQ,GACbhc,KAAK0d,eAAe,CACxB,CAeAiB,iBAAiB/oB,GACb,IAQWgpB,EAAX,IAAWA,IARS,CAChB,CAAEC,MAAO,YAAa9e,KAAM,SAAU5M,QAAS,yBAA0B,EACzE,CAAE0rB,MAAO,mBAAoB9e,KAAM,SAAU5M,QAAS,4BAA6B,EACnF,CAAE0rB,MAAO,sBAAuB9e,KAAM,SAAU5M,QAAS,+BAAgC,EACzF,CAAE0rB,MAAO,YAAa9e,KAAM,SAAU5M,QAAS,2BAA4B,EAC3E,CAAE0rB,MAAO,WAAY9e,KAAM,SAAU5M,QAAS,0BAA2B,GAGvC,CAClC,IAAMgQ,EAAQnD,KAAK8e,eAAelpB,EAAUgpB,EAAWC,KAAK,EAC5D,GAAI,CAAC1b,GAAS,OAAOA,IAAUyb,EAAW7e,KACtC,MAAM,IAAI3N,MAAMwsB,EAAWzrB,OAAO,CAE1C,CAEA,GAAKyC,EAASM,YAAgBN,EAASM,sBAAsB6oB,KAI7D,OAAOnpB,EAHH,MAAM,IAAIxD,MAAM,6BAA6B,CAIrD,CASA0sB,eAAeE,EAAK3G,GAChB,OAAOA,EAAKha,MAAM,GAAG,EAAEif,OAAO,CAAC2B,EAAS5sB,IAAQ4sB,IAAU5sB,GAAM2sB,CAAG,CACvE,CAOAE,2BAA2BtpB,GACjBupB,EAAoBpsB,MAAMiN,KAAK2e,iBAAiB/oB,CAAQ,EAC9D,OAAaD,qBAAqBwpB,CAAiB,CACvD,CASApT,gCAAgClW,EAAQ9B,EAAW0B,GAE/C,IAAM2pB,EAAU,CACZC,mBAAoBrf,KAAKgc,MAAMrjB,OAC/B2mB,eAAgB,EAChBC,YAAa,GACb9mB,QAAS,CAAA,CACb,EAEA,IAAK/F,IAAIyU,EAAI,EAAGA,EAAInH,KAAKgc,MAAMrjB,OAAQwO,CAAC,GAAI,CACxC,IAAMvR,EAAWoK,KAAKgc,MAAM7U,GAEtBrT,EAAS,CACX2E,QAAS,CAAA,EACT3F,SAAU,KACVD,MAAO,IACX,EAEA,IACI,IAAM2sB,EAAiB,CACnB3pB,OAAAA,EACA9B,UAAAA,EACA0B,UAAAA,EACAO,SAAUJ,EAASK,KAAKnB,KACxBoB,WAAYN,EAASK,KACrBG,gBAAiB+Q,CACrB,EAEMrU,EAAWC,MAAMiN,KAAKkf,qBAAqBM,CAAc,EAC/D1rB,EAAOhB,SAAWA,EAClBgB,EAAO2E,QAA8B,MAApB3F,EAAS0C,OAEtB1B,EAAO2E,SACP2mB,EAAQE,cAAc,EAI9B,CAFE,MAAOzsB,GACLiB,EAAOjB,MAAQA,EAAMM,OACzB,CAEAisB,EAAQG,YAAY/gB,KAAK1K,CAAM,CACnC,CAKA,OAHAsrB,EAAQ3mB,QAAU2mB,EAAQC,qBAAuBD,EAAQE,eACzDtf,KAAK0e,WAAW,EAETU,CACX,CACJ,OAEMnS,uBACFC,uBAAuB1I,GACnB,IAAMib,EAAiBzf,KAAKwE,GAE5B,GAA8B,YAA1B,OAAOib,EACP,MAAM,IAAIrtB,0BAA0BoS,cAAyB,EAKjE,OAFeib,EAAeC,KAAK1f,IAAI,EAAEzD,KAAK,CAGlD,CAEAojB,oBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCJ,CAEAC,wBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyDJ,CAEAC,oCACI;;;;;;CAOJ,CAEAC,iCACI;;;;;;;;;;CAWJ,CAEAC,sBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0EJ,CAEAC,qBACI;;;;;;;;;;;;;;;;;;;;;;;;;CA0BJ,CAEAC,mBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyDJ,CAEAC,cACI;;;;;OAMJ,CAEAC,qBACI;;;;UAKJ,CAEAC,mBACI,MAAO,0EACX,CACAC,uBACI,MAAO,sJACX,CAEJ,OAEMjgB,iBACFkgB,eAAeC,GACX,IAAMC,EAAYxgB,KAAKugB,GAEvB,GAAyB,YAArB,OAAOC,EACP,MAAM,IAAIpuB,0BAA0BmuB,cAAoB,EAG5D,OAAOC,EAAUd,KAAK1f,IAAI,EAAEzD,KAAK,CACrC,CAEAkkB,mBAAmBF,GACf,OAAOvgB,KAAKsgB,QAAQC,CAAO,CAC/B,CAEAlgB,oBAAoBkgB,GACVG,EAAM1gB,KAAKsgB,QAAQC,CAAO,EAChC,OAAOvgB,KAAK2gB,aAAaD,CAAG,CAChC,CAEAC,oBAAoBC,GACVvC,GAAQ,IAAIwC,aAAcC,OAAOF,CAAS,EAEhD,MAAO,6BADUG,KAAKvX,OAAOwX,aAAa,GAAG3C,CAAK,CAAC,CAEvD,CAEA5d,qBACI;;;OAIJ,CAEA2E,yBACI;;;OAIJ,CAEAjF,2BACI;;;;OAKJ,CAEAkF,+BACI;;;;OAKJ,CAEA1E,2BACI;;;;;;;;;;;;OAaJ,CAEAD,yBACI;;;OAIJ,CAEAE,0BACI;;;OAIJ,CAEAC,yBACI;;;;OAKJ,CAEAE,wBACI;;;OAIJ,CAEAC,yBACI;;;;;OAMJ,CAEAF,kCACI;;;OAIJ,CAEAG,uBACI;;;OAIJ,CAEAX,0BACI;;;;OAKJ,CAEA2gB,oBACI;;;;;;;;;;;CAYJ,CAEA/b,iBACI;;;;CAKJ,CAEAC,kBACI;;;;CAKJ,CAEA5E,kBACI;;;;CAKJ,CAEAC,sBACI;;;;;;CAOJ,CACJ,OAEM0P,qBAEFpQ,cACIE,KAAKkhB,QAAQ,CACjB,CAEAC,aAEI,OAAO5F,UACX,CAEA2F,UACIlhB,KAAKohB,UAAU,EACfphB,KAAKqhB,QAAQ,CACjB,CAEAD,YACI,IAAME,EAAmB1kB,SAASwH,cAAc,MAAM,EAKhDmd,GAJND,EAAiBE,IAAM,aACvBF,EAAiBpnB,KAAO,+BACxB0C,SAAS6kB,KAAK7b,YAAY0b,CAAgB,EAEhB1kB,SAASwH,cAAc,MAAM,GAMjDsd,GALNH,EAAkBC,IAAM,aACxBD,EAAkBrnB,KAAO,4BACzBqnB,EAAkBI,YAAc,cAChC/kB,SAAS6kB,KAAK7b,YAAY2b,CAAiB,EAE1B3kB,SAASwH,cAAc,MAAM,GAC9Csd,EAASF,IAAM,aACfE,EAASxnB,KAAO,2EAChB0C,SAAS6kB,KAAK7b,YAAY8b,CAAQ,CACtC,CAEAL,UACI,IAAMhiB,EAAQzC,SAASwH,cAAc,OAAO,EAC5C/E,EAAMuiB,aAAa,KAAM,aAAa,EACtCviB,EAAM6U,YAAclU,KAAKmhB,WAAW,EACpCvkB,SAAS6kB,KAAK7b,YAAYvG,CAAK,CACnC,CACJ,CAEAzC,SAASilB,cAAc,IAAIC,YAAY,gBAAiB,CACpDC,OAAQ,CACJvpB,WAAW,IAAIsC,MAAOknB,YAAY,EAClC7uB,QAAS,iCACb,CACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/js/src/api.js b/js/src/api.js index 942c2cd..40b8e78 100644 --- a/js/src/api.js +++ b/js/src/api.js @@ -100,7 +100,7 @@ const userConfirmEmailDoboard = async (emailConfirmationToken) => { }; const createTaskDoboard = async (sessionId, taskDetails) => { - const accountId = taskDetails.accountId + const accountId = taskDetails.accountId; const data = { session_id: sessionId, project_token: taskDetails.projectToken, diff --git a/js/src/loaders/SpotFixSVGLoader.js b/js/src/loaders/SpotFixSVGLoader.js index f9b750b..56e5df7 100644 --- a/js/src/loaders/SpotFixSVGLoader.js +++ b/js/src/loaders/SpotFixSVGLoader.js @@ -158,6 +158,24 @@ class SpotFixSVGLoader { +`; + } + + static iconPlus() { + return ` + + + +`; + } + + static iconMaximize() { + return ` + + + + + `; } } diff --git a/js/src/loaders/SpotFixTemplatesLoader.js b/js/src/loaders/SpotFixTemplatesLoader.js index 327ba61..dba544f 100644 --- a/js/src/loaders/SpotFixTemplatesLoader.js +++ b/js/src/loaders/SpotFixTemplatesLoader.js @@ -13,16 +13,22 @@ class SpotFixTemplatesLoader { static all_issues() { return ` -
+
All spots
+ + + + + +
@@ -43,7 +49,7 @@ class SpotFixTemplatesLoader { static concrete_issue() { return ` -
+
@@ -51,13 +57,22 @@ class SpotFixTemplatesLoader {
{{issueTitle}}
+ + + + + +
+
@@ -118,7 +133,7 @@ class SpotFixTemplatesLoader { static create_issue() { return ` -
+
@@ -128,6 +143,9 @@ class SpotFixTemplatesLoader { + + +
diff --git a/js/src/widget.js b/js/src/widget.js index 627c999..ecd29a5 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -20,8 +20,11 @@ class CleanTalkWidgetDoboard { this.selectedText = selectedData?.selectedText || ''; this.init(type); this.srcVariables = { + widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), + iconPlus: SpotFixSVGLoader.getAsDataURI('iconPlus'), + iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'), chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'), buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'), buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'), @@ -209,8 +212,9 @@ class CleanTalkWidgetDoboard { projectToken: this.params.projectToken, projectId: this.params.projectId, accountId: this.params.accountId, - taskMeta: JSON.stringify(this.selectedData), + taskMeta: JSON.stringify(this.selectedData ? this.selectedData : {pageURL:"http://localhost/"}), }; + if ( userEmail ) { taskDetails.userEmail = userEmail } @@ -282,8 +286,10 @@ class CleanTalkWidgetDoboard { this.type_name = templateName; templateVariables = { selectedText: this.selectedText, + widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', currentDomain: document.location.hostname || '', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), + iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'), iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), ...this.srcVariables }; @@ -303,7 +309,9 @@ class CleanTalkWidgetDoboard { case 'all_issues': templateName = 'all_issues'; this.type_name = templateName; - templateVariables = {...this.srcVariables}; + templateVariables = { + widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', + ...this.srcVariables}; break; case 'user_menu': templateName = 'user_menu'; @@ -337,6 +345,7 @@ class CleanTalkWidgetDoboard { templateVariables = { issueTitle: '...', issueComments: [], + widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', issuesCounter: getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll), ...this.srcVariables, }; @@ -356,6 +365,7 @@ class CleanTalkWidgetDoboard { const selection = window.getSelection(); const sessionIdExists = !!localStorage.getItem('spotfix_session_id'); const email = localStorage.getItem('spotfix_email'); + if (sessionIdExists && email && !email.includes('spotfix_')) { document.querySelector('.doboard_task_widget-login').classList.add('hidden'); } @@ -385,7 +395,15 @@ class CleanTalkWidgetDoboard { }); break; case 'all_issues': - spotFixRemoveHighlights(); + const container = document.querySelector('.doboard_task_widget-container'); + + if(+localStorage.getItem('maximize')){ + container.classList.add('doboard_task_widget-container-maximize'); + } else { + container.classList.remove('doboard_task_widget-container-maximize'); + } + + spotFixRemoveHighlights(); let issuesQuantityOnPage = 0; if (!this.allTasksData?.length) { this.allTasksData = await getAllTasks(this.params); @@ -518,10 +536,8 @@ class CleanTalkWidgetDoboard { break; case 'concrete_issue': - tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId); const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId); - // Update issue title in the interface const issueTitleElement = document.querySelector('.doboard_task_widget-issue-title'); if (issueTitleElement) { @@ -531,21 +547,30 @@ class CleanTalkWidgetDoboard { templateVariables.issueTitle = taskDetails?.issueTitle; templateVariables.issueComments = taskDetails?.issueComments; - widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables); - document.body.appendChild(widgetContainer); // Highlight the task's selected text let nodePath = null; const currentTaskData = this.allTasksData.find((element) => String(element.taskId) === String(taskDetails.taskId)); let meta = null; + if (currentTaskData && currentTaskData.taskMeta) { try { meta = JSON.parse(currentTaskData.taskMeta); nodePath = meta.nodePath || null; } catch (e) { nodePath = null; meta = null; } } + + templateVariables.taskPageUrl = meta.pageURL; + const taskFormattedPageUrl = meta.pageURL.replace(window.location.origin, ''); + templateVariables.taskFormattedPageUrl = taskFormattedPageUrl.length < 2 + ? meta.pageURL.replace(window.location.protocol + '/', '') : taskFormattedPageUrl; + + widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables); + document.body.appendChild(widgetContainer); + // remove old highlights before adding new ones spotFixRemoveHighlights(); + if (meta && nodePath) { // Pass the task meta object as an array spotFixHighlightElements([meta], this); @@ -711,6 +736,22 @@ class CleanTalkWidgetDoboard { jogoutUserDoboard(this.params.accountId); }) || ''; + document.getElementById('addNewTaskButton')?.addEventListener('click', () => { + spotFixShowWidget(); + }) || ''; + + document.getElementById('maximizeWidgetContainer')?.addEventListener('click', () => { + const container = document.querySelector('.doboard_task_widget-container'); + + if(+localStorage.getItem('maximize') && container.classList.contains('doboard_task_widget-container-maximize')){ + localStorage.setItem('maximize', '0'); + container.classList.remove('doboard_task_widget-container-maximize'); + } else { + localStorage.setItem('maximize', '1'); + container.classList.add('doboard_task_widget-container-maximize'); + } + }) || ''; + document.querySelector('#doboard_task_widget-user_menu-signlog_button')?.addEventListener('click', () => { spotFixShowWidget(); }) || ''; @@ -890,6 +931,7 @@ class CleanTalkWidgetDoboard { hide() { spotFixRemoveHighlights(); this.createWidgetElement('wrap'); + } wrapElementWithSpotfixHighlight(element) { diff --git a/styles/doboard-widget.css b/styles/doboard-widget.css index 3288220..f729935 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -80,8 +80,17 @@ 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: 400px; + width: 430px; max-height: calc(100vh - 40px); display: flex; flex-direction: column; @@ -92,6 +101,9 @@ .doboard_task_widget-container { max-height: calc(60vh - 40px); } + .doboard_task_widget-container-maximize { + max-height: calc(60vh - 40px); + } } .doboard_task_widget-header { @@ -368,6 +380,7 @@ .doboard_task_widget-submit_button { height: 48px; width: 100%; + max-width: 400px; margin-bottom: 10px; color: #FFFFFF; background: #22A475; @@ -1093,6 +1106,14 @@ max-height: 90vh; } + .doboard_task_widget-header { + padding: 8px; + } + + .doboard_task_widget-issue-title { + max-width: 70px; + } + .doboard_task_widget-container { width: 100%; max-width: 290px; @@ -1100,6 +1121,13 @@ max-height: 90vh; } + .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; From 6cae373dd8d65d609eae0128811be51cccc61bdb Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Tue, 23 Dec 2025 02:13:59 +0400 Subject: [PATCH 09/20] Fix. Ability to change the size --- dist/doboard-widget-bundle.js | 38 ++++++++++++++---------- dist/doboard-widget-bundle.min.js | 10 +++---- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/loaders/SpotFixTemplatesLoader.js | 6 ++-- js/src/widget.js | 30 +++++++++++-------- 5 files changed, 49 insertions(+), 37 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 0ea5802..c1aa358 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -642,7 +642,6 @@ class CleanTalkWidgetDoboard { this.selectedText = selectedData?.selectedText || ''; this.init(type); this.srcVariables = { - widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), iconPlus: SpotFixSVGLoader.getAsDataURI('iconPlus'), @@ -908,7 +907,6 @@ class CleanTalkWidgetDoboard { this.type_name = templateName; templateVariables = { selectedText: this.selectedText, - widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', currentDomain: document.location.hostname || '', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'), @@ -931,9 +929,7 @@ class CleanTalkWidgetDoboard { case 'all_issues': templateName = 'all_issues'; this.type_name = templateName; - templateVariables = { - widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', - ...this.srcVariables}; + templateVariables = {...this.srcVariables}; break; case 'user_menu': templateName = 'user_menu'; @@ -967,7 +963,6 @@ class CleanTalkWidgetDoboard { templateVariables = { issueTitle: '...', issueComments: [], - widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', issuesCounter: getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll), ...this.srcVariables, }; @@ -980,9 +975,15 @@ class CleanTalkWidgetDoboard { // remove highlights before any screen called spotFixRemoveHighlights(); - + const container = document.querySelector('.doboard_task_widget-container'); switch (type) { case 'create_issue': + + if(container && +localStorage.getItem('maximize')){ + container.classList.add('doboard_task_widget-container-maximize'); + } else if(container) { + container.classList.remove('doboard_task_widget-container-maximize'); + } // highlight selected item during task creation const selection = window.getSelection(); const sessionIdExists = !!localStorage.getItem('spotfix_session_id'); @@ -1017,11 +1018,9 @@ class CleanTalkWidgetDoboard { }); break; case 'all_issues': - const container = document.querySelector('.doboard_task_widget-container'); - - if(+localStorage.getItem('maximize')){ + if(container && +localStorage.getItem('maximize')){ container.classList.add('doboard_task_widget-container-maximize'); - } else { + } else if(container) { container.classList.remove('doboard_task_widget-container-maximize'); } @@ -1158,6 +1157,11 @@ class CleanTalkWidgetDoboard { break; case 'concrete_issue': + if(container && +localStorage.getItem('maximize')){ + container.classList.add('doboard_task_widget-container-maximize'); + } else if(container) { + container.classList.remove('doboard_task_widget-container-maximize'); + } tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId); const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId); // Update issue title in the interface @@ -1186,7 +1190,8 @@ class CleanTalkWidgetDoboard { const taskFormattedPageUrl = meta.pageURL.replace(window.location.origin, ''); templateVariables.taskFormattedPageUrl = taskFormattedPageUrl.length < 2 ? meta.pageURL.replace(window.location.protocol + '/', '') : taskFormattedPageUrl; - + templateVariables.contenerClasess = +localStorage.getItem('maximize') + ? 'doboard_task_widget-container-maximize doboard_task_widget-container' : 'doboard_task_widget-container' widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables); document.body.appendChild(widgetContainer); @@ -1327,6 +1332,7 @@ class CleanTalkWidgetDoboard { sendButton.disabled = false; }); } + break; default: @@ -2665,7 +2671,6 @@ function spotFixRetrieveNodeFromPath(path) { return node; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} @@ -2844,6 +2849,7 @@ function storageProvidedTaskHasUnreadUpdates(taskId) { } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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}`; /** * File uploader handler for managing file attachments with validation and upload capabilities */ @@ -3251,7 +3257,7 @@ class SpotFixTemplatesLoader { static all_issues() { return ` -
+
@@ -3287,7 +3293,7 @@ class SpotFixTemplatesLoader { static concrete_issue() { return ` -
+
@@ -3371,7 +3377,7 @@ class SpotFixTemplatesLoader { static create_issue() { return ` -
+
diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 6d6cf5f..5d592b4 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={widgetContainerClases:+localStorage.getItem("maximize")?"doboard_task_widget-container doboard_task_widget-container-maximize":"doboard_task_widget-container",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,widgetContainerClases:+localStorage.getItem("maximize")?"doboard_task_widget-container doboard_task_widget-container-maximize":"doboard_task_widget-container",currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={widgetContainerClases:+localStorage.getItem("maximize")?"doboard_task_widget-container doboard_task_widget-container-maximize":"doboard_task_widget-container",...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],widgetContainerClases:+localStorage.getItem("maximize")?"doboard_task_widget-container doboard_task_widget-container-maximize":"doboard_task_widget-container",issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}switch(d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights(),e){case"create_issue":var c=window.getSelection(),g=!!localStorage.getItem("spotfix_session_id"),p=localStorage.getItem("spotfix_email");g&&p&&!p.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===c.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(c).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":g=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")?g.classList.add("doboard_task_widget-container-maximize"):g.classList.remove("doboard_task_widget-container-maximize"),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();c=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",c&&(l.userName=c.name||"Guest",l.email=c.email||"",c?.avatar?.s)&&(l.avatar=c?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var c=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=c.length<2?i.pageURL.replace(window.location.protocol+"/",""):c,d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),A=[],v=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),T){var E=T[S];e+=this.loadTemplate("concrete_issue_messages",E)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:M,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function D(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),_=localStorage.getItem("spotfix_email");p&&_&&!_.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize"),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,u=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();_=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",_&&(l.userName=_.name||"Guest",l.email=_.email||"",_?.avatar?.s)&&(l.avatar=_?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var _=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=_.length<2?i.pageURL.replace(window.location.protocol+"/",""):_,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),A=[],y=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[C];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:T,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0img{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}`;class FileUploader{constructor(e){this.files=[],this.maxFileSize=5242880,this.maxTotalSize=26214400,this.maxFiles=5,this.allowedTypes=["image/jpeg","image/png","image/gif","application/pdf","text/plain","application/msword"],this.escapeHtmlHandler=e,this.SIZE_UNITS=["Bytes","KB","MB","GB"]}init(){this.initializeElements(),this.bindFilesInputChange()}initializeElements(){this.fileInput=document.getElementById("doboard_task_widget__file-upload__file-input-button"),this.fileList=document.getElementById("doboard_task_widget__file-upload__file-list"),this.uploaderWrapper=document.getElementById("doboard_task_widget__file-upload__wrapper"),this.errorMessage=document.getElementById("doboard_task_widget__file-upload__error"),this.fileInput&&this.fileList&&this.errorMessage&&!this.uploaderWrapper||console.warn("File uploader elements not found")}bindFilesInputChange(){this.fileInput&&this.fileInput.addEventListener("change",e=>this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
@@ -13,7 +13,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
`),e.querySelector(".doboard_task_widget__file-upload__remove-btn").addEventListener("click",()=>this.removeFile(a)),e}formatFileSize(e){var t;return 0===e?"0 Bytes":(t=Math.floor(Math.log(e)/Math.log(1024)),parseFloat((e/Math.pow(1024,t)).toFixed(2))+" "+this.SIZE_UNITS[t])}showError(e){this.errorMessage&&(this.errorMessage.textContent=e,this.errorMessage.style.display="block")}clearError(){this.errorMessage&&(this.errorMessage.textContent="",this.errorMessage.style.display="none")}hasFiles(){return 0e?.[t],e)}async sendSingleAttachment(e){e=await this.validateFileData(e);return attachmentAddDoboard(e)}async sendAttachmentsForComment(t,a,i){var o={preparedFilesCount:this.files.length,sentFilesCount:0,fileResults:[],success:!0};for(let e=0;e +
@@ -45,7 +45,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
`}static concrete_issue(){return` -
+
@@ -117,7 +117,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
`}static create_issue(){return` -
+
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 5a3f2fb..bb9972e 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container',\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 logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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:\"http://localhost/\"}),\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 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 widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container',\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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'all_issues':\r\n templateName = 'all_issues';\r\n this.type_name = templateName;\r\n templateVariables = {\r\n widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container',\r\n ...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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 widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container',\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\r\n switch (type) {\r\n case 'create_issue':\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 const container = document.querySelector('.doboard_task_widget-container');\r\n\r\n if(+localStorage.getItem('maximize')){\r\n container.classList.add('doboard_task_widget-container-maximize');\r\n } else {\r\n container.classList.remove('doboard_task_widget-container-maximize');\r\n }\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 || '';\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 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\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 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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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:#FFF;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:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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\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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","widgetContainerClases","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","iconPlus","iconMaximize","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","selection","getSelection","sessionIdExists","add","spotFixScrollToNodePath","spotFixGetSelectedData","nodePath","positionWidgetContainer","getTaskCount","widgetElementClasses","currentTarget","spotFixOpenWidget","container","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","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","position","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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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 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\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 || '';\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 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 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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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\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\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:#FFF;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:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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 * 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","iconPlus","iconMaximize","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","container","add","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","position","slice","marker","insertText","idClass","cls","path","scrollIntoView","block","spans","affectedParents","Set","elementSelectionClassName","parent","tooltip","firstChild","removeChild","normalize","imageSelectionClassName","every","index","isInteger","imgNode","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","spotFixIsElementInRange","FILTER_ACCEPT","FILTER_REJECT","nextNode","startElement","spotFixGetElementFromNode","endElement","spotFixIsElementPartiallySelected","spotFixFindNearbyElements","elementRange","createRange","selectNode","compareBoundaryPoints","Range","START_TO_START","END_TO_END","elementRect","rangeRect","right","left","elements","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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 dba544f..c1921e9 100644 --- a/js/src/loaders/SpotFixTemplatesLoader.js +++ b/js/src/loaders/SpotFixTemplatesLoader.js @@ -13,7 +13,7 @@ class SpotFixTemplatesLoader { static all_issues() { return ` -
+
@@ -49,7 +49,7 @@ class SpotFixTemplatesLoader { static concrete_issue() { return ` -
+
@@ -133,7 +133,7 @@ class SpotFixTemplatesLoader { static create_issue() { return ` -
+
diff --git a/js/src/widget.js b/js/src/widget.js index ecd29a5..9b0e48b 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -20,7 +20,6 @@ class CleanTalkWidgetDoboard { this.selectedText = selectedData?.selectedText || ''; this.init(type); this.srcVariables = { - widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), iconEllipsesMore: SpotFixSVGLoader.getAsDataURI('iconEllipsesMore'), iconPlus: SpotFixSVGLoader.getAsDataURI('iconPlus'), @@ -286,7 +285,6 @@ class CleanTalkWidgetDoboard { this.type_name = templateName; templateVariables = { selectedText: this.selectedText, - widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', currentDomain: document.location.hostname || '', buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), iconMaximize: SpotFixSVGLoader.getAsDataURI('iconMaximize'), @@ -309,9 +307,7 @@ class CleanTalkWidgetDoboard { case 'all_issues': templateName = 'all_issues'; this.type_name = templateName; - templateVariables = { - widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', - ...this.srcVariables}; + templateVariables = {...this.srcVariables}; break; case 'user_menu': templateName = 'user_menu'; @@ -345,7 +341,6 @@ class CleanTalkWidgetDoboard { templateVariables = { issueTitle: '...', issueComments: [], - widgetContainerClases: +localStorage.getItem('maximize') ? 'doboard_task_widget-container doboard_task_widget-container-maximize' : 'doboard_task_widget-container', issuesCounter: getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll), ...this.srcVariables, }; @@ -358,9 +353,15 @@ class CleanTalkWidgetDoboard { // remove highlights before any screen called spotFixRemoveHighlights(); - + const container = document.querySelector('.doboard_task_widget-container'); switch (type) { case 'create_issue': + + if(container && +localStorage.getItem('maximize')){ + container.classList.add('doboard_task_widget-container-maximize'); + } else if(container) { + container.classList.remove('doboard_task_widget-container-maximize'); + } // highlight selected item during task creation const selection = window.getSelection(); const sessionIdExists = !!localStorage.getItem('spotfix_session_id'); @@ -395,11 +396,9 @@ class CleanTalkWidgetDoboard { }); break; case 'all_issues': - const container = document.querySelector('.doboard_task_widget-container'); - - if(+localStorage.getItem('maximize')){ + if(container && +localStorage.getItem('maximize')){ container.classList.add('doboard_task_widget-container-maximize'); - } else { + } else if(container) { container.classList.remove('doboard_task_widget-container-maximize'); } @@ -536,6 +535,11 @@ class CleanTalkWidgetDoboard { break; case 'concrete_issue': + if(container && +localStorage.getItem('maximize')){ + container.classList.add('doboard_task_widget-container-maximize'); + } else if(container) { + container.classList.remove('doboard_task_widget-container-maximize'); + } tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId); const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId); // Update issue title in the interface @@ -564,7 +568,8 @@ class CleanTalkWidgetDoboard { const taskFormattedPageUrl = meta.pageURL.replace(window.location.origin, ''); templateVariables.taskFormattedPageUrl = taskFormattedPageUrl.length < 2 ? meta.pageURL.replace(window.location.protocol + '/', '') : taskFormattedPageUrl; - + templateVariables.contenerClasess = +localStorage.getItem('maximize') + ? 'doboard_task_widget-container-maximize doboard_task_widget-container' : 'doboard_task_widget-container' widgetContainer.innerHTML = this.loadTemplate('concrete_issue', templateVariables); document.body.appendChild(widgetContainer); @@ -705,6 +710,7 @@ class CleanTalkWidgetDoboard { sendButton.disabled = false; }); } + break; default: From 66a7d13ca5d5bd959ec7ce3896ff7a31ce1ed4e0 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Tue, 23 Dec 2025 03:42:33 +0400 Subject: [PATCH 10/20] Upd. Added a new icon --- dist/doboard-widget-bundle.js | 63 ++++++++++++---------- dist/doboard-widget-bundle.min.js | 47 ++++++++--------- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/loaders/SpotFixSVGLoader.js | 46 ++++++++-------- js/src/loaders/SpotFixTemplatesLoader.js | 10 ++-- js/src/widget.js | 5 +- styles/doboard-widget.css | 67 ++++++++++++------------ 7 files changed, 123 insertions(+), 117 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index c1aa358..692085b 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -649,9 +649,10 @@ class CleanTalkWidgetDoboard { chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'), buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'), buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'), - logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'), + logoDoBoardGreen: SpotFixSVGLoader.getAsDataURI('logoDoBoardGreen'), logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'), iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'), + iconMarker: SpotFixSVGLoader.getAsDataURI('iconMarker'), iconSpotPublic: SpotFixSVGLoader.getAsDataURI('iconSpotPublic'), iconSpotPrivate: SpotFixSVGLoader.getAsDataURI('iconSpotPrivate'), iconLinkChain: SpotFixSVGLoader.getAsDataURI('iconLinkChain'), @@ -940,7 +941,7 @@ class CleanTalkWidgetDoboard { iconEye: SpotFixSVGLoader.getAsDataURI('iconEye'), iconDoor: SpotFixSVGLoader.getAsDataURI('iconDoor'), chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'), - buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'), + buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), userName: 'Guest', email: '', ...this.srcVariables}; @@ -2671,6 +2672,7 @@ function spotFixRetrieveNodeFromPath(path) { return node; } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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;top:-80px;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;height:54px;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#review_content_button_text{color:#D5991A;margin-left:4px;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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} @@ -2849,7 +2851,6 @@ function storageProvidedTaskHasUnreadUpdates(taskId) { } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#FFF;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:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:"";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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}`; /** * File uploader handler for managing file attachments with validation and upload capabilities */ @@ -3260,7 +3261,7 @@ class SpotFixTemplatesLoader {
- + All spots
@@ -3380,7 +3381,7 @@ class SpotFixTemplatesLoader {
- + Report an issue
@@ -3492,7 +3493,7 @@ class SpotFixTemplatesLoader { Back
- +
@@ -3544,7 +3545,7 @@ class SpotFixTemplatesLoader { static wrap() { return `
- +
`; @@ -3553,7 +3554,7 @@ class SpotFixTemplatesLoader { static wrap_review() { return ` `; } @@ -3596,7 +3597,7 @@ class SpotFixSVGLoader { static chevronBack() { return ` - + `; } @@ -3610,14 +3611,6 @@ class SpotFixSVGLoader { static buttonCloseScreen() { return ` - - -`; - } - - static buttonCloseScreenDark() { - return ` - `; @@ -3646,13 +3639,20 @@ class SpotFixSVGLoader { `; } - static logoDoBoardWhite() { + static logoDoBoardGreen() { return ` - + `; } +// static logoDoBoardWhite() { +// return ` +// +// +// `; +// } + static logoDoBoardWrap() { return ` @@ -3692,10 +3692,10 @@ class SpotFixSVGLoader { } static iconEllipsesMore() { - return ` - - - + return ` + + + `; } @@ -3732,21 +3732,26 @@ class SpotFixSVGLoader { static iconPlus() { return ` - - + + `; } static iconMaximize() { return ` - - - - + + + + `; } + + static iconMarker() { + return ``; + } } class SpotFixSourcesLoader { diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 5d592b4..316763c 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardWhite:SpotFixSVGLoader.getAsDataURI("logoDoBoardWhite"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreenDark:SpotFixSVGLoader.getAsDataURI("buttonCloseScreenDark"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),_=localStorage.getItem("spotfix_email");p&&_&&!_.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize"),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,u=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();_=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",_&&(l.userName=_.name||"Guest",l.email=_.email||"",_?.avatar?.s)&&(l.avatar=_?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var _=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=_.length<2?i.pageURL.replace(window.location.protocol+"/",""):_,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),A=[],y=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[C];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:T,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize"),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHN0RXZ0OndoZW49IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNC4wIChNYWNpbnRvc2gpIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuPRTtsAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAL0UExURUdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKGw/wAAAAAAAAAAAAAAAAAAAAAAAAAAAKOy/6Sw/gAAAAAAAAAAAAAAAIKPz6Kw/6Cw/6Kx/6Gw/6Gw/6Gw/6Gv/qCw/6Gw/6i0/6Oy/67D/6Gw/6Gx/6ez/6u9/6Gw/6Kx/6i5/624/6Cy/wAAAJ6r/6Oy/6W1/qCv/4aR1LPE/4eU0o+d3qGw/6Sy/6Ku/6Cv/KGw/6Cu/4WT1KKr/5up9Q8RGhodK7jI/4mY1K27/6Cv/8PW/7LE/6Gw/7nL/1RchUVLbbnN/0pXfBQVHjY5U2Vwm2ZwnyMmNrDB/6e2/629/7XG/6Kw/6Kw/67A/629/3N+vKe3/77Q/52r7HmEtrPE/6Oz8RgaKbTF/7TG/xgaKnaCtsLV/6Sv/7TI/wCv/6Gw/wAAAKCv/6e2/73O/6a1/6Oz/6u7/7zN/6q5/7fJ/629/7PD/wAAAQwNE5+u/7DA/6S0/7bH/7XG/6Gx/6i4/yUoOQQFBwICA7HC/7nL/zM4UouY3RcaJK+//y4ySL7Q/ygsPx8iME9WfTA1TXJ8sp2s9VxkjoSQ0RESGl9ok5up9XR/t213rRQWHkRKbJKf53mEwUxSeKGv+qy8/5Ce4jk+WQkKDjxBYCouQpSh6lZfiEFHZVpijJ6t/GFqmWdxoT5DY4eU1mp0qXiDvHyHxZak5n2KxlFZg8LU/32Kv4mV2ZSj7FBYgJGe50VLbS7TJ5EAAACrdFJOUwAPCsvhFe/y+w0C/fc8LUGd9SWvHnW1BPOTw/7NCbtcyNpxsr+4WVKbIETkCOiij0d96tQGEhCmijeFGGxw0Gp6qZhKxmbeYCtNG9NMgKzX5iduYwXl2GVVAZNEVKrs9opx5j/ZFcMIER77LlsYnDAbbDlLDH3+/v2wIlDxy8E95PP9un2PvJ1Pv2VX9kmOqeG89a2m+efFg2aYq9fPqexM0cHR6vWeMdh9ztTtu0oAAA1/SURBVHja7FxnWBPZGs5SQoAAocMiJEjv0qQEpMhCgAVRUFFEaYq9d7f3vb333u99ZpIAafTQ24Jg13XtfV3b7t1d7/65cyaTBiFMkknbZ94f6DOZnG/eOd/56jmhUEiQIEGCBAkSJEiQIEGCBAkSJEiQIEGCBAkS1o6cUAeH0FVWT8OeBaNg2Vs3D6dlMIZlTlZNJAtwoNHB3xyrJmKLMAgqYYch/9haM49YBximp1AoKcicOMRaOxFfCsXX2omgqhVWUmL1qoUtdpr1L3YV87vOyh1igYxHgZU7RATZiGLRvL8NwRZiuRy+DTwcARFHckYsB6l+MOyXasUEUjwichM8C1bEBcBwQMWKAs+E3AiPQGsLTVwSy1fDcxGQ5FPmYjWhSmA4IwnWgjhGuI0V0HDxj1N/bhrdz49OV79GzXexcBrMF1XefFCCd7ULpyTV0TG1hONS7Z0QqjJTLzItmEZRsvwxVzOyXDWshVjXLEaF/J7kIgulESEPEO0S3FK0WLPoBDvsxkURFkhjTxj2dOURvgvd6xvhid0ctsfSeCRi9jXSFd/9rvkBsm+UWdZ0YGs80mO+O6qaDx5srlK9spKBrXpXC1rkaAoIh2Ro+GxXTX1d7ZbSho2vvLKxoXRLbV19zWY5fR+ZfbaYRe+PPk9M9VwSO9eXboLmYFPp+l9vQ2+ojkG/6m8RNGxkqzxvdgq4rf49DSTk2P5ePeCSmod+OcgCXD0b9R0BL826vKF2uxTSju3HPgBq6Yz6lBJz8/BCfUKhuhVdV1m6EAsUnaXfQRZ9MOp7oszLIwpV8lD1dKOyCcILbhNCBdXNCi+z1kjQWD1P7dqBV6UQfnC5/9lPyUeNhRnrLIGoVkSqXtpbK9WFB9Av4fsUbzDOCvMlKqFzeGzYCOkMLvSvf+aitsus/kNVr9bt5kKQPkz47/yDZj5/wkQDDJULx1/ViwdYKIK//BXEXmbJUaKAA4hR8WSNGyG90Tn8xzeBOzKHEUazj5Uqy0MKGYBOwWEwJcvMFLerhHuVkIH46FMwYq7JFQvNoQjkweUJRsCYplYukIBQlQtkA2QwOiWnboIowbQ8XgYvT5lxv94NEcDko8dg1OUmJVKo9u72bpISQITLE02CANSkKSF4dcq0tknKhYiYEtFXsImdiZ1aaLKbEBoIpPxbIKI3HY9q4LvYioVOFA+I2/u/dmToapMRWaQ6IVs3QYRByv8M1O1MxSNDzd4fI44HMiWjYGxTVe0iEVk+igirm0AiUGvPBDJ4vml4pDggstASlq9XdM4bbUQS4Q7PAE+bYppiNSJqTaDr2kyfGBp8Y4jQGYGE0rPI8MUmIVIOeh9YY639soRLKBGp4Js5VQCjqJVbYohq6+kzvpRQHhBX9AlafU10M2LNbmV2vHpbjVZ4hOAJQXSL24FMNOJOqHnZK41AwtctfYUqB3pheSaz5E8ionlArb03ZETQwkr6El9CabglxKhNRcjL9uim0T9AhBPhCkCC1aEQFZPgRphGJarMRTCDivzFwpNdnYTzgKChM4iAt34arJS5ItGDABrL8xQD+vnkZjiBfZZJ2B7eesgIED5ApuPmCYqrt4+7YqOBp6FZCpMlHyspMnwpuFKsUknbYgwivLbbiIjXwPhLwyMVDW2WIdF9uLxP6x4fLq9n5ioLabuMwQNqFX2MiPgCa2vFRsTL5yU5XE8a0fLmf0GOvXp5cbHsvzuNQgTi30dEfLNTWSnPKZBvMtBn3b+A9SrhNPVvhygTht3GISICqfvIb9SsZhr2MIwXdOWxBGvqMzizPgBvB9tIUmocIhLg2/t/ry6Wg71XuyW68cjFZmNOZrBuDXJZRm7zUeMQ6XqEiBg7unmWZA5mPnUq4aGdF9g2WoOHr0AiE9mSqTEOD0h8ZxCGzz5onLtobeE5fQztiEe/kKnpIyc7Ral5n9QoPDpFj5AAZYy7T4P0TPTB4nXqe1DnUcYg5LMEVMnqjEGEyx3/L8jbp4fqNC5dqg59+XC0Tztf5Jmj2Of+207iaUjH+eIvgISHw7UaxXsU4i59LQW9o9XseTMS1NeyXvKlvC0mmAXE6xl+dv8tMP4lYd+H8/T1wX4v2lIcRICdc9aSCbhhdjDzd72CcQLz3JYhft+X9wZkox8WdZbOF8OCBhNjYR5sMI7W03YR8g2K/aevdwm6eESE8i3j/K4jd6ewgTu+FHChhqp55K+ClfG3FoBO8ZoF4nq5n4UHJ06PXuP3ClsN4MJt7Rvii6+fvo0lU/DAvWfDyMtpmvecBojwFz41ALYhZC+YopQVyrm09598ckrCl7S16EWCJx4WdR++OzkoH2/s7rPhISTPkVbOK32xal1Na8MAx1YwJ2Y5TZGodNy4//l5sUAkFrbgN8lSnnBIIOq7/PDjMcVAgzdmugVdUi5ihX81v2xXXM0HPyQfx3e2wGtxgUr22zHxfOb6VbFgWCIW8lq1B+o8oVgiGG47debTb6YGlENMnr7eK+pDtIrb8O4OLYId6XiODeAnAlTMO5TWrnySwUvTVx4+vXy1TyIQiCRd4jZhH4/Ha2np7m5B/u0TCsVdkh6BQCK8evnJuSu3O1Tew2D/3VGxYBxdbFsqm7VKxUcEp2opUJLzwzcH1SoTA2cnb508/fjJmTunHiAvv+2aeHwc4cRr5Z668+jpxXMnb01eGlD7xs2Rc0euCbpagC9pqtuxkEh8qoVrsavj4Hd/8KNLg3M3wQ90XJrqn5yYmB4ZmZ643T811jGg4ab+KxfODwnGeUDpGtbXrKMseKoM32IH5jdYNyJOFErV/nd+/L3+DlgntJ8deT7zdZugpw31q6V1jVW45OEzvws7xPmweWfdaz+5MjLV0b4wh5tTt54/Hr06zu+5xgOGrmH3vuN45aAOEcfmLjRE4eiZ52/9/qFjb4xeOHfy3nQ/oknq+tY+0DHWP33v5LkLX53nSfiicWGLbM/pvh3N+EVwcIYosqAxzoDNklXbPjj0/i9/8XPo/NejZz7/5MLMxYsXZy48eXpm9M55qEXcyx/u7WrrQ7Rpe8OH6+trtoKUQAfjEoc3aJSF8XaGFpCb9zZWHnr3Z2//+W9/7+3p6e2VSIaA7eprObppY9OW2vX/rmzc26z7sCvRWgLOwpDWxEp3RluP79jfWHPgxIYTBw7U7N9xfGuz/oMtRxOrBAJSXfNCx1RXUXxYYlk0sOKDTq1SrByUZ0HHO/QqB6kU6CzkUIQrVqArjCaqZGoWKEum+hz6dZMXsVlZZj2Mbp/FMqSIPautwDTTwYjYiHi6oW0FzY0eU2Ipk0FMo0fWeguQj+Xuk5uRYioSKXtUW2/lRGwQ9EhMVgZ+MYzsDKNvxg/k5DBUziwHl3kQZjXU2tNJIWXF9r5GIsEuLgtRPbNsl0Cs1ZyzYcDOM5PJIdQC2HCYZWlr1I4nE75hAIs8s+Pj1I9BU1nxmVnRXgYunBS2y9rMeBZVbWh6knG2cMjhqSHdo8WxPP0T1y7fw7bR4Ue0nGzYe5avTfT3ZM16OzJ4GtkggteWXuTPcteUwNKphbZhaf5l3llF4cVuGa4eHlElbHtwDNyeXRLl4eGa4VYcXpTlXeafFmZbSNX0/LAfy78oHUy2cY096OnGoBGMy6rMEDua9sw8wNmZRqO7Ozi4u9NoNOcA7XfTKoLSs1zQti0wLSHG5JGhvpMcbAXMTLOl0mCD4Ey1TcvMUV1qYJMenGFEIos0bma1YWdELE5PC1oW567L87vHLQtKS88Nd4uywSmIMCz0omJTOS7FzKzE9Pz4cp9Q2+TgQruKJCr4ORFqUoVdYXCybahPeXx+emIWs9iFkxqLe+qJhs6q6+SbEsgGP/DCDkzxddJrMRoDoFQJ636AU6+f3PGCcZUT9fO87nqdsNPzR5BAKYdunN9OQoe2MRURR3djHUxEJ3sxxVREKNn/b+dsdhIGojBqoZRCY4QIgokSLUyCJSSQEONGFiILExZKoj4GT8Y7ynRouVBiMr93c09YsOrH7XSmZ4Z2rLxx1SnV+opv1ynvr8Wnp/1ayZw1PsXDsh9UFRtEvZB0bKkGfnkYm2iYj14EbJctXBWyYMCGI6b7tPxzwXavPReFGMg9XonJnr4FZ+exYr+QCnjqN1DMLSjPdjtob7hYh1Ox38ad/UJELptyG33ZtAcquZBluirGn2D0xaB+ma7ZLW0Xkufe7l+CU8mFlDO36uzuTmH6Y26kt1dVKCTPrUVim12VXLgqw3++6GOT8eck/eLtWrt7b7cQmDsaq+bCA3bzA17M9rMeJ4UYyT1t4pN/5p1dWtq5hU73Dva9E53u10ln1809O/xetTyvleyHQckToz786uWevzGFzWa2wvAjeWOq80Lq7nOP8YqqIGsbMz7VnbnPPWXFwGJPyFaSq6xxY84XH+aN+Mtl7nmNf+UaH/gPb7I6vWDwnMqas3ruvxMr+QmOCYNVyTVN3mGj9KNvsFiIIbS3TnYeHiTrnq7BYnEwZ75LuQGDxSI3WP76e6BvsFhAg/0eJQbED6sQ4waLeWkZNVjUzm7UYHGHX4MGi35DNGawWFgwWCwsGCwWVgyWIAiCIAiCIAiCIAiCIAiCIAgU/gAyRDCHjvicJQAAAABJRU5ErkJggg==');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0img{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}`;class FileUploader{constructor(e){this.files=[],this.maxFileSize=5242880,this.maxTotalSize=26214400,this.maxFiles=5,this.allowedTypes=["image/jpeg","image/png","image/gif","application/pdf","text/plain","application/msword"],this.escapeHtmlHandler=e,this.SIZE_UNITS=["Bytes","KB","MB","GB"]}init(){this.initializeElements(),this.bindFilesInputChange()}initializeElements(){this.fileInput=document.getElementById("doboard_task_widget__file-upload__file-input-button"),this.fileList=document.getElementById("doboard_task_widget__file-upload__file-list"),this.uploaderWrapper=document.getElementById("doboard_task_widget__file-upload__wrapper"),this.errorMessage=document.getElementById("doboard_task_widget__file-upload__error"),this.fileInput&&this.fileList&&this.errorMessage&&!this.uploaderWrapper||console.warn("File uploader elements not found")}bindFilesInputChange(){this.fileInput&&this.fileInput.addEventListener("change",e=>this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
@@ -16,7 +16,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
- + All spots
@@ -120,7 +120,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
- + Report an issue
@@ -224,7 +224,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) Back
- +
@@ -272,25 +272,21 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
`}static wrap(){return`
- +
`}static wrap_review(){return` `}static fixedHtml(){return'

Finished

'}static fixedTaskHtml(){return'

This issue already fixed

'}}class SpotFixSVGLoader{static loadSVG(e){var t=this[e];if("function"!=typeof t)throw new Error(`Template method '${e}' not found`);return t.call(this).trim()}static getAsRawSVG(e){return this.loadSVG(e)}static getAsDataURI(e){e=this.loadSVG(e);return this.svgToDataURI(e)}static svgToDataURI(e){e=(new TextEncoder).encode(e);return"data:image/svg+xml;base64,"+btoa(String.fromCharCode(...e))}static chevronBack(){return` - + `}static chevronBackDark(){return` `}static buttonCloseScreen(){return` - - -`}static buttonCloseScreenDark(){return` - `}static buttonSendMessage(){return` @@ -308,9 +304,9 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) `}static buttonPaperClip(){return` -`}static logoDoBoardWhite(){return` +`}static logoDoBoardGreen(){return` - + `}static logoDoBoardWrap(){return` @@ -329,10 +325,10 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) `}static iconLinkChain(){return` -`}static iconEllipsesMore(){return` - - - +`}static iconEllipsesMore(){return` + + + `}static iconAvatar(){return` @@ -353,14 +349,15 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0) `}static iconPlus(){return` - - + + `}static iconMaximize(){return` - - - - + + + + -`}}class SpotFixSourcesLoader{constructor(){this.loadAll()}getCSSCode(){return spotFixCSS}loadAll(){this.loadFonts(),this.loadCSS()}loadFonts(){var e=document.createElement("link"),e=(e.rel="preconnect",e.href="https://fonts.googleapis.com",document.head.appendChild(e),document.createElement("link")),e=(e.rel="preconnect",e.href="https://fonts.gstatic.com",e.crossOrigin="crossorigin",document.head.appendChild(e),document.createElement("link"));e.rel="stylesheet",e.href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",document.head.appendChild(e)}loadCSS(){var e=document.createElement("style");e.setAttribute("id","spotfix_css"),e.textContent=this.getCSSCode(),document.head.appendChild(e)}}document.dispatchEvent(new CustomEvent("spotFixLoaded",{detail:{timestamp:(new Date).toISOString(),message:"All scripts loaded successfully"}})); +`}static iconMarker(){return``}}class SpotFixSourcesLoader{constructor(){this.loadAll()}getCSSCode(){return spotFixCSS}loadAll(){this.loadFonts(),this.loadCSS()}loadFonts(){var e=document.createElement("link"),e=(e.rel="preconnect",e.href="https://fonts.googleapis.com",document.head.appendChild(e),document.createElement("link")),e=(e.rel="preconnect",e.href="https://fonts.gstatic.com",e.crossOrigin="crossorigin",document.head.appendChild(e),document.createElement("link"));e.rel="stylesheet",e.href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",document.head.appendChild(e)}loadCSS(){var e=document.createElement("style");e.setAttribute("id","spotfix_css"),e.textContent=this.getCSSCode(),document.head.appendChild(e)}}document.dispatchEvent(new CustomEvent("spotFixLoaded",{detail:{timestamp:(new Date).toISOString(),message:"All scripts loaded successfully"}})); //# sourceMappingURL=doboard-widget-bundle.min.js.map diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index bb9972e..2b0fe6f 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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 logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'),\r\n logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'),\r\n iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'),\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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 buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'),\r\n userName: 'Guest',\r\n 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 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\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 || '';\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 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 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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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\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\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:#FFF;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:8px 16px;background:#1C7857;border-radius:8px 8px 0 0;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{border:none;box-shadow:none;position:relative;padding:0;cursor:pointer;width:56px;height:56px;border-radius:50%;background-color:#1c7857;opacity:.6;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:24px;height:24px}.doboard_task_widget-wrap::after{content:\"\";position:absolute;left:-2px;bottom:-6px;width:0;height:0;border-style:solid;border-radius:20%;border-width:20px 22px 0 0;border-color:#1c7857 transparent transparent;transform:rotate(30deg)}.wrap_review{width:160px;border-radius:16px;height:52px}.wrap_review:hover{background-color:#1c7857}#review_content_button_text{color:#fff;margin-left:4px;font-size:16px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-5px;right:-5px;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 * 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 buttonCloseScreenDark() {\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 logoDoBoardWhite() {\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\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","CleanTalkWidgetDoboard","widgetElement","savedIssuesQuantityOnPage","savedIssuesQuantityAll","allTasksData","srcVariables","constructor","type","this","init","buttonCloseScreen","SpotFixSVGLoader","getAsDataURI","iconEllipsesMore","iconPlus","iconMaximize","chevronBack","buttonPaperClip","buttonSendMessage","logoDoBoardWhite","logoDoBoardWrap","iconSpotWidgetWrapPencil","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","buttonCloseScreenDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","container","add","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","position","slice","marker","insertText","idClass","cls","path","scrollIntoView","block","spans","affectedParents","Set","elementSelectionClassName","parent","tooltip","firstChild","removeChild","normalize","imageSelectionClassName","every","index","isInteger","imgNode","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","spotFixIsElementInRange","FILTER_ACCEPT","FILTER_REJECT","nextNode","startElement","spotFixGetElementFromNode","endElement","spotFixIsElementPartiallySelected","spotFixFindNearbyElements","elementRange","createRange","selectNode","compareBoundaryPoints","Range","START_TO_START","END_TO_END","elementRect","rangeRect","right","left","elements","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 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\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 || '';\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 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 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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHN0RXZ0OndoZW49IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNC4wIChNYWNpbnRvc2gpIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuPRTtsAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAL0UExURUdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKGw/wAAAAAAAAAAAAAAAAAAAAAAAAAAAKOy/6Sw/gAAAAAAAAAAAAAAAIKPz6Kw/6Cw/6Kx/6Gw/6Gw/6Gw/6Gv/qCw/6Gw/6i0/6Oy/67D/6Gw/6Gx/6ez/6u9/6Gw/6Kx/6i5/624/6Cy/wAAAJ6r/6Oy/6W1/qCv/4aR1LPE/4eU0o+d3qGw/6Sy/6Ku/6Cv/KGw/6Cu/4WT1KKr/5up9Q8RGhodK7jI/4mY1K27/6Cv/8PW/7LE/6Gw/7nL/1RchUVLbbnN/0pXfBQVHjY5U2Vwm2ZwnyMmNrDB/6e2/629/7XG/6Kw/6Kw/67A/629/3N+vKe3/77Q/52r7HmEtrPE/6Oz8RgaKbTF/7TG/xgaKnaCtsLV/6Sv/7TI/wCv/6Gw/wAAAKCv/6e2/73O/6a1/6Oz/6u7/7zN/6q5/7fJ/629/7PD/wAAAQwNE5+u/7DA/6S0/7bH/7XG/6Gx/6i4/yUoOQQFBwICA7HC/7nL/zM4UouY3RcaJK+//y4ySL7Q/ygsPx8iME9WfTA1TXJ8sp2s9VxkjoSQ0RESGl9ok5up9XR/t213rRQWHkRKbJKf53mEwUxSeKGv+qy8/5Ce4jk+WQkKDjxBYCouQpSh6lZfiEFHZVpijJ6t/GFqmWdxoT5DY4eU1mp0qXiDvHyHxZak5n2KxlFZg8LU/32Kv4mV2ZSj7FBYgJGe50VLbS7TJ5EAAACrdFJOUwAPCsvhFe/y+w0C/fc8LUGd9SWvHnW1BPOTw/7NCbtcyNpxsr+4WVKbIETkCOiij0d96tQGEhCmijeFGGxw0Gp6qZhKxmbeYCtNG9NMgKzX5iduYwXl2GVVAZNEVKrs9opx5j/ZFcMIER77LlsYnDAbbDlLDH3+/v2wIlDxy8E95PP9un2PvJ1Pv2VX9kmOqeG89a2m+efFg2aYq9fPqexM0cHR6vWeMdh9ztTtu0oAAA1/SURBVHja7FxnWBPZGs5SQoAAocMiJEjv0qQEpMhCgAVRUFFEaYq9d7f3vb333u99ZpIAafTQ24Jg13XtfV3b7t1d7/65cyaTBiFMkknbZ94f6DOZnG/eOd/56jmhUEiQIEGCBAkSJEiQIEGCBAkSJEiQIEGCBAkS1o6cUAeH0FVWT8OeBaNg2Vs3D6dlMIZlTlZNJAtwoNHB3xyrJmKLMAgqYYch/9haM49YBximp1AoKcicOMRaOxFfCsXX2omgqhVWUmL1qoUtdpr1L3YV87vOyh1igYxHgZU7RATZiGLRvL8NwRZiuRy+DTwcARFHckYsB6l+MOyXasUEUjwichM8C1bEBcBwQMWKAs+E3AiPQGsLTVwSy1fDcxGQ5FPmYjWhSmA4IwnWgjhGuI0V0HDxj1N/bhrdz49OV79GzXexcBrMF1XefFCCd7ULpyTV0TG1hONS7Z0QqjJTLzItmEZRsvwxVzOyXDWshVjXLEaF/J7kIgulESEPEO0S3FK0WLPoBDvsxkURFkhjTxj2dOURvgvd6xvhid0ctsfSeCRi9jXSFd/9rvkBsm+UWdZ0YGs80mO+O6qaDx5srlK9spKBrXpXC1rkaAoIh2Ro+GxXTX1d7ZbSho2vvLKxoXRLbV19zWY5fR+ZfbaYRe+PPk9M9VwSO9eXboLmYFPp+l9vQ2+ojkG/6m8RNGxkqzxvdgq4rf49DSTk2P5ePeCSmod+OcgCXD0b9R0BL826vKF2uxTSju3HPgBq6Yz6lBJz8/BCfUKhuhVdV1m6EAsUnaXfQRZ9MOp7oszLIwpV8lD1dKOyCcILbhNCBdXNCi+z1kjQWD1P7dqBV6UQfnC5/9lPyUeNhRnrLIGoVkSqXtpbK9WFB9Av4fsUbzDOCvMlKqFzeGzYCOkMLvSvf+aitsus/kNVr9bt5kKQPkz47/yDZj5/wkQDDJULx1/ViwdYKIK//BXEXmbJUaKAA4hR8WSNGyG90Tn8xzeBOzKHEUazj5Uqy0MKGYBOwWEwJcvMFLerhHuVkIH46FMwYq7JFQvNoQjkweUJRsCYplYukIBQlQtkA2QwOiWnboIowbQ8XgYvT5lxv94NEcDko8dg1OUmJVKo9u72bpISQITLE02CANSkKSF4dcq0tknKhYiYEtFXsImdiZ1aaLKbEBoIpPxbIKI3HY9q4LvYioVOFA+I2/u/dmToapMRWaQ6IVs3QYRByv8M1O1MxSNDzd4fI44HMiWjYGxTVe0iEVk+igirm0AiUGvPBDJ4vml4pDggstASlq9XdM4bbUQS4Q7PAE+bYppiNSJqTaDr2kyfGBp8Y4jQGYGE0rPI8MUmIVIOeh9YY639soRLKBGp4Js5VQCjqJVbYohq6+kzvpRQHhBX9AlafU10M2LNbmV2vHpbjVZ4hOAJQXSL24FMNOJOqHnZK41AwtctfYUqB3pheSaz5E8ionlArb03ZETQwkr6El9CabglxKhNRcjL9uim0T9AhBPhCkCC1aEQFZPgRphGJarMRTCDivzFwpNdnYTzgKChM4iAt34arJS5ItGDABrL8xQD+vnkZjiBfZZJ2B7eesgIED5ApuPmCYqrt4+7YqOBp6FZCpMlHyspMnwpuFKsUknbYgwivLbbiIjXwPhLwyMVDW2WIdF9uLxP6x4fLq9n5ioLabuMwQNqFX2MiPgCa2vFRsTL5yU5XE8a0fLmf0GOvXp5cbHsvzuNQgTi30dEfLNTWSnPKZBvMtBn3b+A9SrhNPVvhygTht3GISICqfvIb9SsZhr2MIwXdOWxBGvqMzizPgBvB9tIUmocIhLg2/t/ry6Wg71XuyW68cjFZmNOZrBuDXJZRm7zUeMQ6XqEiBg7unmWZA5mPnUq4aGdF9g2WoOHr0AiE9mSqTEOD0h8ZxCGzz5onLtobeE5fQztiEe/kKnpIyc7Ral5n9QoPDpFj5AAZYy7T4P0TPTB4nXqe1DnUcYg5LMEVMnqjEGEyx3/L8jbp4fqNC5dqg59+XC0Tztf5Jmj2Of+207iaUjH+eIvgISHw7UaxXsU4i59LQW9o9XseTMS1NeyXvKlvC0mmAXE6xl+dv8tMP4lYd+H8/T1wX4v2lIcRICdc9aSCbhhdjDzd72CcQLz3JYhft+X9wZkox8WdZbOF8OCBhNjYR5sMI7W03YR8g2K/aevdwm6eESE8i3j/K4jd6ewgTu+FHChhqp55K+ClfG3FoBO8ZoF4nq5n4UHJ06PXuP3ClsN4MJt7Rvii6+fvo0lU/DAvWfDyMtpmvecBojwFz41ALYhZC+YopQVyrm09598ckrCl7S16EWCJx4WdR++OzkoH2/s7rPhISTPkVbOK32xal1Na8MAx1YwJ2Y5TZGodNy4//l5sUAkFrbgN8lSnnBIIOq7/PDjMcVAgzdmugVdUi5ihX81v2xXXM0HPyQfx3e2wGtxgUr22zHxfOb6VbFgWCIW8lq1B+o8oVgiGG47debTb6YGlENMnr7eK+pDtIrb8O4OLYId6XiODeAnAlTMO5TWrnySwUvTVx4+vXy1TyIQiCRd4jZhH4/Ha2np7m5B/u0TCsVdkh6BQCK8evnJuSu3O1Tew2D/3VGxYBxdbFsqm7VKxUcEp2opUJLzwzcH1SoTA2cnb508/fjJmTunHiAvv+2aeHwc4cRr5Z668+jpxXMnb01eGlD7xs2Rc0euCbpagC9pqtuxkEh8qoVrsavj4Hd/8KNLg3M3wQ90XJrqn5yYmB4ZmZ643T811jGg4ab+KxfODwnGeUDpGtbXrKMseKoM32IH5jdYNyJOFErV/nd+/L3+DlgntJ8deT7zdZugpw31q6V1jVW45OEzvws7xPmweWfdaz+5MjLV0b4wh5tTt54/Hr06zu+5xgOGrmH3vuN45aAOEcfmLjRE4eiZ52/9/qFjb4xeOHfy3nQ/oknq+tY+0DHWP33v5LkLX53nSfiicWGLbM/pvh3N+EVwcIYosqAxzoDNklXbPjj0/i9/8XPo/NejZz7/5MLMxYsXZy48eXpm9M55qEXcyx/u7WrrQ7Rpe8OH6+trtoKUQAfjEoc3aJSF8XaGFpCb9zZWHnr3Z2//+W9/7+3p6e2VSIaA7eprObppY9OW2vX/rmzc26z7sCvRWgLOwpDWxEp3RluP79jfWHPgxIYTBw7U7N9xfGuz/oMtRxOrBAJSXfNCx1RXUXxYYlk0sOKDTq1SrByUZ0HHO/QqB6kU6CzkUIQrVqArjCaqZGoWKEum+hz6dZMXsVlZZj2Mbp/FMqSIPautwDTTwYjYiHi6oW0FzY0eU2Ipk0FMo0fWeguQj+Xuk5uRYioSKXtUW2/lRGwQ9EhMVgZ+MYzsDKNvxg/k5DBUziwHl3kQZjXU2tNJIWXF9r5GIsEuLgtRPbNsl0Cs1ZyzYcDOM5PJIdQC2HCYZWlr1I4nE75hAIs8s+Pj1I9BU1nxmVnRXgYunBS2y9rMeBZVbWh6knG2cMjhqSHdo8WxPP0T1y7fw7bR4Ue0nGzYe5avTfT3ZM16OzJ4GtkggteWXuTPcteUwNKphbZhaf5l3llF4cVuGa4eHlElbHtwDNyeXRLl4eGa4VYcXpTlXeafFmZbSNX0/LAfy78oHUy2cY096OnGoBGMy6rMEDua9sw8wNmZRqO7Ozi4u9NoNOcA7XfTKoLSs1zQti0wLSHG5JGhvpMcbAXMTLOl0mCD4Ey1TcvMUV1qYJMenGFEIos0bma1YWdELE5PC1oW567L87vHLQtKS88Nd4uywSmIMCz0omJTOS7FzKzE9Pz4cp9Q2+TgQruKJCr4ORFqUoVdYXCybahPeXx+emIWs9iFkxqLe+qJhs6q6+SbEsgGP/DCDkzxddJrMRoDoFQJ636AU6+f3PGCcZUT9fO87nqdsNPzR5BAKYdunN9OQoe2MRURR3djHUxEJ3sxxVREKNn/b+dsdhIGojBqoZRCY4QIgokSLUyCJSSQEONGFiILExZKoj4GT8Y7ynRouVBiMr93c09YsOrH7XSmZ4Z2rLxx1SnV+opv1ynvr8Wnp/1ayZw1PsXDsh9UFRtEvZB0bKkGfnkYm2iYj14EbJctXBWyYMCGI6b7tPxzwXavPReFGMg9XonJnr4FZ+exYr+QCnjqN1DMLSjPdjtob7hYh1Ox38ad/UJELptyG33ZtAcquZBluirGn2D0xaB+ma7ZLW0Xkufe7l+CU8mFlDO36uzuTmH6Y26kt1dVKCTPrUVim12VXLgqw3++6GOT8eck/eLtWrt7b7cQmDsaq+bCA3bzA17M9rMeJ4UYyT1t4pN/5p1dWtq5hU73Dva9E53u10ln1809O/xetTyvleyHQckToz786uWevzGFzWa2wvAjeWOq80Lq7nOP8YqqIGsbMz7VnbnPPWXFwGJPyFaSq6xxY84XH+aN+Mtl7nmNf+UaH/gPb7I6vWDwnMqas3ruvxMr+QmOCYNVyTVN3mGj9KNvsFiIIbS3TnYeHiTrnq7BYnEwZ75LuQGDxSI3WP76e6BvsFhAg/0eJQbED6sQ4waLeWkZNVjUzm7UYHGHX4MGi35DNGawWFgwWCwsGCwWVgyWIAiCIAiCIAiCIAiCIAiCIAgU/gAyRDCHjvicJQAAAABJRU5ErkJggg==');`;\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;top:-80px;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;height:54px;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#review_content_button_text{color:#D5991A;margin-left:4px;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\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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","container","add","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","position","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/SpotFixSVGLoader.js b/js/src/loaders/SpotFixSVGLoader.js index 56e5df7..62b61f2 100644 --- a/js/src/loaders/SpotFixSVGLoader.js +++ b/js/src/loaders/SpotFixSVGLoader.js @@ -27,7 +27,7 @@ class SpotFixSVGLoader { static chevronBack() { return ` - + `; } @@ -41,14 +41,6 @@ class SpotFixSVGLoader { static buttonCloseScreen() { return ` - - -`; - } - - static buttonCloseScreenDark() { - return ` - `; @@ -77,13 +69,20 @@ class SpotFixSVGLoader { `; } - static logoDoBoardWhite() { + static logoDoBoardGreen() { return ` - + `; } +// static logoDoBoardWhite() { +// return ` +// +// +// `; +// } + static logoDoBoardWrap() { return ` @@ -123,10 +122,10 @@ class SpotFixSVGLoader { } static iconEllipsesMore() { - return ` - - - + return ` + + + `; } @@ -163,19 +162,24 @@ class SpotFixSVGLoader { static iconPlus() { return ` - - + + `; } static iconMaximize() { return ` - - - - + + + + `; } + + static iconMarker() { + return ``; + } } diff --git a/js/src/loaders/SpotFixTemplatesLoader.js b/js/src/loaders/SpotFixTemplatesLoader.js index c1921e9..4e8425c 100644 --- a/js/src/loaders/SpotFixTemplatesLoader.js +++ b/js/src/loaders/SpotFixTemplatesLoader.js @@ -16,7 +16,7 @@ class SpotFixTemplatesLoader {
- + All spots
@@ -136,7 +136,7 @@ class SpotFixTemplatesLoader {
- + Report an issue
@@ -248,7 +248,7 @@ class SpotFixTemplatesLoader { Back
- +
@@ -300,7 +300,7 @@ class SpotFixTemplatesLoader { static wrap() { return `
- +
`; @@ -309,7 +309,7 @@ class SpotFixTemplatesLoader { static wrap_review() { return ` `; } diff --git a/js/src/widget.js b/js/src/widget.js index 9b0e48b..d82aafc 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -27,9 +27,10 @@ class CleanTalkWidgetDoboard { chevronBack: SpotFixSVGLoader.getAsDataURI('chevronBack'), buttonPaperClip: SpotFixSVGLoader.getAsDataURI('buttonPaperClip'), buttonSendMessage: SpotFixSVGLoader.getAsDataURI('buttonSendMessage'), - logoDoBoardWhite: SpotFixSVGLoader.getAsDataURI('logoDoBoardWhite'), + logoDoBoardGreen: SpotFixSVGLoader.getAsDataURI('logoDoBoardGreen'), logoDoBoardWrap: SpotFixSVGLoader.getAsDataURI('logoDoBoardWrap'), iconSpotWidgetWrapPencil: SpotFixSVGLoader.getAsDataURI('iconSpotWidgetWrapPencil'), + iconMarker: SpotFixSVGLoader.getAsDataURI('iconMarker'), iconSpotPublic: SpotFixSVGLoader.getAsDataURI('iconSpotPublic'), iconSpotPrivate: SpotFixSVGLoader.getAsDataURI('iconSpotPrivate'), iconLinkChain: SpotFixSVGLoader.getAsDataURI('iconLinkChain'), @@ -318,7 +319,7 @@ class CleanTalkWidgetDoboard { iconEye: SpotFixSVGLoader.getAsDataURI('iconEye'), iconDoor: SpotFixSVGLoader.getAsDataURI('iconDoor'), chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'), - buttonCloseScreenDark: SpotFixSVGLoader.getAsDataURI('buttonCloseScreenDark'), + buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), userName: 'Guest', email: '', ...this.srcVariables}; diff --git a/styles/doboard-widget.css b/styles/doboard-widget.css index f729935..a87c75a 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -52,7 +52,7 @@ color: #40484F; } .doboard_task_widget-header * { - color: #FFFFFF; + color: #252A2F; margin: 0; } @@ -110,9 +110,12 @@ display: flex; height: 41px; min-height: 41px; - padding: 8px 16px; - background: #1C7857; + padding: 0px 16px; + /*background: #1C7857;*/ + background-color: #EBF0F4; border-radius: 8px 8px 0 0; + border: 1px solid #BBC7D1; + border-bottom: none; justify-content: space-between; align-items: center; color: #FFFFFF; @@ -175,38 +178,27 @@ /*** `WRAP` INTERFACE ***/ .doboard_task_widget-wrap { - border: none; box-shadow: none; - position: relative; + position: fixed; + top: -80px; + right: -50px; padding: 0; cursor: pointer; - width: 56px; - height: 56px; - border-radius: 50%; - background-color: #1c7857; - opacity: 0.6; + width: 69px; + height: 52px; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + background-color: rgba(255, 255, 255, 0.9); + border: 1px #EBF0F4 solid; display: flex; align-items: center; justify-content: center; } .doboard_task_widget-wrap img { - width: 24px; - height: 24px; -} - -.doboard_task_widget-wrap::after { - content: ""; - position: absolute; - left: -2px; - bottom: -6px; - width: 0; - height: 0; - border-style: solid; - border-radius: 20%; - border-width: 20px 22px 0 0; - border-color: #1c7857 transparent transparent transparent; - transform: rotate(30deg); + width: 32px; + height: 32px; + transform: scaleX(-1); } .doboard_task_widget-wrap.hidden { @@ -214,19 +206,26 @@ } .wrap_review { - width: 160px; - border-radius: 16px; - height: 52px; + width: 164px; + height: 54px; + top: -100px; +} + +.wrap_review img { + width: 28px; + height: 28px; + transform: scaleX(-1); } .wrap_review:hover { - background-color: #1c7857; + background-color: rgb(255, 255, 255); } #review_content_button_text { - color: white; + color: #D5991A; margin-left: 4px; - font-size: 16px; + font-weight: 600; + font-size: 14px; text-transform: none !important; } @@ -236,8 +235,8 @@ #doboard_task_widget-task_count { position: absolute; - top: -5px; - right: -5px; + top: -12px; + right: 4px; width: 22px; height: 22px; opacity: 1; From 51f4f8bdd5d4e509256f291ee48a9747a9c41e61 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Tue, 23 Dec 2025 03:47:46 +0400 Subject: [PATCH 11/20] Fix. Shortened the code --- dist/doboard-widget-bundle.js | 20 ++++++++++---------- dist/doboard-widget-bundle.min.js | 2 +- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/handlers.js | 8 ++++++++ js/src/widget.js | 12 ++---------- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 692085b..ae74cf1 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -620,6 +620,14 @@ function checkLogInOutButtonsVisible (){ } } +function changeSize(container){ + if(container && +localStorage.getItem('maximize')){ + container.classList.add('doboard_task_widget-container-maximize'); + } else if(container) { + container.classList.remove('doboard_task_widget-container-maximize'); + } +} + /** * Widget class to create a task widget */ @@ -1019,11 +1027,7 @@ class CleanTalkWidgetDoboard { }); break; case 'all_issues': - if(container && +localStorage.getItem('maximize')){ - container.classList.add('doboard_task_widget-container-maximize'); - } else if(container) { - container.classList.remove('doboard_task_widget-container-maximize'); - } + changeSize(container); spotFixRemoveHighlights(); let issuesQuantityOnPage = 0; @@ -1158,11 +1162,7 @@ class CleanTalkWidgetDoboard { break; case 'concrete_issue': - if(container && +localStorage.getItem('maximize')){ - container.classList.add('doboard_task_widget-container-maximize'); - } else if(container) { - container.classList.remove('doboard_task_widget-container-maximize'); - } + changeSize(container); tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId); const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId); // Update issue title in the interface diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 316763c..ff21a41 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,4 +1,4 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize"),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 2b0fe6f..4c8c63e 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 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\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 || '';\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 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 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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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;top:-80px;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;height:54px;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#review_content_button_text{color:#D5991A;margin-left:4px;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\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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","versionFromLS","spotfixVersion","iconEye","iconDoor","chevronBackDark","Array","isArray","e","issueComments","issuesCounter","loadTemplate","appendChild","spotFixRemoveHighlights","container","add","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","position","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":"AAAA,IAAMA,gBAAkB,0BAWlBC,eAAiBC,MAAMC,EAAMC,EAAQC,EAAYC,KAAAA,KACnD,GAAI,CAACH,GAAwB,UAAhB,OAAOA,EAChB,MAAM,IAAII,MAAM,6BAA6B,EAGjD,GAAI,CAACH,GAA4B,UAAlB,OAAOA,EAClB,MAAM,IAAIG,MAAM,+BAA+B,EAGnD,GAAkBD,KAAAA,IAAdD,GAAiD,UAArB,OAAOA,GAA+C,UAArB,OAAOA,EACpE,MAAM,IAAIE,MAAM,sCAAsC,EAG1D,IACWC,EADLC,EAAW,IAAIC,SACrB,IAAWF,KAAOL,EACVA,EAAKQ,eAAeH,CAAG,GACnBL,MAAAA,EAAKK,IACLC,EAASG,OAAOJ,EAAKL,EAAKK,EAAI,EAK1CK,IAAIC,EAEAA,EADcR,KAAAA,IAAdD,EACiBL,oBAAmBK,KAAaD,EAEhCJ,gBAAH,IAAsBI,EAGxC,IACI,IAAIW,IAAID,CAAW,CAGvB,CAFE,MAAOE,GACL,MAAM,IAAIT,MAAM,yBAAyBO,CAAa,CAC1D,CAEAD,IAAII,EACJ,IACIA,EAAWC,MAAMC,MAAML,EAAa,CAChCV,OAAQ,OACRgB,KAAMX,CACV,CAAC,CAGL,CAFE,MAAOY,GACL,MAAM,IAAId,MAAM,kBAAkBc,EAAaC,OAAS,CAC5D,CAEAT,IAAIU,EACJ,IACIA,EAAeL,MAAMD,EAASO,KAAK,CAGvC,CAFE,MAAOC,GACL,MAAM,IAAIlB,MAAM,2CAA2C,CAC/D,CAEA,GAAI,CAACgB,GAAwC,UAAxB,OAAOA,EACxB,MAAM,IAAIhB,MAAM,qCAAqC,EAGzD,GAAI,CAACgB,EAAapB,KACd,MAAM,IAAII,MAAM,uCAAuC,EAG3D,GAAI,CAACgB,EAAapB,KAAKuB,iBACnB,MAAM,IAAInB,MAAM,2CAA2C,EAG/D,GAA2C,WAAvCgB,EAAapB,KAAKuB,iBAElB,MADMC,EAAeJ,EAAapB,KAAKyB,mBAAqB,4CACtD,IAAIrB,MAAMoB,CAAY,EAGhC,GAA2C,YAAvCJ,EAAapB,KAAKuB,iBAClB,OAAOH,EAAapB,KAGxB,MAAM,IAAII,MAAM,6BAA6BgB,EAAapB,KAAKuB,gBAAkB,CACrF,EAEMG,wBAA0B3B,MAAO4B,IAC7B3B,EAAO,CACT4B,yBAA0BC,mBAAmBF,CAAsB,CACvE,EACMG,EAASf,MAAMjB,eAAeE,EAAM,oBAAoB,EAC9D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdC,SAAUN,EAAOM,SACjBC,gBAAiBP,EAAOP,gBAC5B,CACJ,EAEMe,kBAAoBvC,MAAOgC,EAAWQ,KACxC,IAAMrC,EAAYqC,EAAYrC,UACxBF,EAAO,CACTgC,WAAYD,EACZS,cAAeD,EAAYE,aAC3BC,WAAYH,EAAYI,UACxBT,QAASU,aAAaC,QAAQ,iBAAiB,EAC/CC,KAAMP,EAAYQ,UAClBC,QAAST,EAAYU,gBACrBC,KAAMX,EAAYY,SAClBC,UAAW,QACf,EAEA,MAAO,CACHC,QAFWtC,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,GAE5CoD,OACnB,CACJ,EAEMC,yBAA2BxD,MAAOG,EAAW6B,EAAWsB,EAAQL,EAASP,EAAce,EAAS,YAC5FxD,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfa,QAASD,EACTL,QAASA,EACTQ,OAAQA,CACZ,EAEA,MAAO,CACHC,WAFW1C,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,GAE5CwD,UACtB,CACJ,EAEMC,qBAAuB5D,MAAO6D,IAChC,IAAM1D,EAAY0D,EAASC,OAAO3D,UAC5BF,EAAO,CACTgC,WAAY4B,EAAS7B,UACrBS,cAAeoB,EAASC,OAAOpB,aAC/BqB,WAAYF,EAASC,OAAO3D,UAC5BwD,WAAYE,EAASH,UACrBM,SAAUH,EAASI,SACnBC,KAAML,EAASM,WACfC,iBAAkBP,EAASQ,eAC/B,EACerD,MAAMjB,eAAeE,EAAM,iBAAkBE,CAAS,CAEzE,EAEMmE,oBAAsBtE,MAAO0C,EAAcvC,EAAWiC,EAAOmC,EAAUC,KACrEvE,EAAO,CACPwC,cAAeC,EACfqB,WAAY5D,EACZsE,iBAAkBrC,CACtB,EACIA,GAASmC,IACTtE,EAAKmC,MAAQA,EACbnC,EAAK8C,KAAOwB,GAEVxC,EAASf,MAAMjB,eAAeE,EAAM,mBAAmB,EAC7D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdsC,cAA+C,IAAhC3C,EAAO4C,qBACtBC,iBAAkB7C,EAAOL,kBACzBY,gBAAiBP,EAAOP,iBACxBqD,mBAAoB9C,EAAO4C,oBAC/B,CACJ,EAEMG,iBAAmB9E,MAAOoC,EAAO2C,KAC7B9E,EAAO,CACTmC,MAAOA,EACP2C,SAAUA,CACd,EACMhD,EAASf,MAAMjB,eAAeE,EAAM,gBAAgB,EAC1D,MAAO,CACH+B,UAAWD,EAAOE,WAClBC,OAAQH,EAAOI,QACfC,MAAOL,EAAOK,MACdsC,cAA+C,IAAhC3C,EAAO4C,qBACtBC,iBAAkB7C,EAAOL,kBACzBY,gBAAiBP,EAAOP,iBACxBqD,mBAAoB9C,EAAO4C,oBAC/B,CACJ,EAEMK,kBAAoBhF,MAAOG,IAC7B,IAAM6B,EAAYa,aAAaC,QAAQ,oBAAoB,EACxDd,GAAa7B,IACNF,EAAO,CACTgC,WAAYD,CAChB,EAG+B,aADhBhB,MAAMjB,eAAeE,EAAM,mBAAoBE,CAAS,GAC7DqB,oBACNqB,aAAaoC,WAAW,eAAe,EACvCpC,aAAaoC,WAAW,oBAAoB,EAC5CpC,aAAaoC,WAAW,iBAAiB,EACzCpC,aAAaqC,QAAQ,2BAA4B,GAAG,EAGhE,EAEMC,gBAAkBnF,MAAO0C,EAAcV,EAAW7B,EAAWyC,EAAWV,KACpEjC,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfC,WAAYC,EACZS,UAAW,QACf,EACKnB,IACDjC,EAAKkC,QAAUD,GAGbkD,GADSpE,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,GAC1CiF,MAAMC,IAAIC,IAAQ,CACnChC,OAAQgC,EAAK/B,QACbP,UAAWsC,EAAKvC,KAChBwC,eAAgBD,EAAKE,QACrBC,YAAaH,EAAKI,QAClBC,oBAAqBL,EAAKM,gBAC1BxC,SAAUkC,EAAKnC,KACf0C,WAAYP,EAAK7B,MACpB,EAAC,EAIF,OAFAqC,sBAAsBV,CAAK,EAEpBA,CACX,EAGMW,wBAA0B/F,MAAOgC,EAAW7B,EAAWuC,EAAce,EAAS,YAC1ExD,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfe,OAAQA,CACZ,EAEA,OADezC,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,GACpD6F,SAASX,IAAIpC,IAAW,CAClCK,OAAQL,EAAQM,QAChBG,UAAWT,EAAQU,WACnBzB,OAAQe,EAAQd,QAChB8D,YAAahD,EAAQA,QACrBiD,YAAajD,EAAQuC,QACrB/B,OAAQR,EAAQQ,OAChB0C,WAAYlD,EAAQmD,SACvB,EAAC,CACN,EAEMC,eAAiBrG,MAAOgC,EAAWU,EAAcvC,EAAW+B,KACxDjC,EAAO,CACTgC,WAAYD,EACZS,cAAeC,CACnB,EACIR,IAAQjC,EAAKkC,QAAUD,GAErBH,EAASf,MAAMjB,eAAeE,EAAM,WAAYE,CAAS,EAC/D,OAAO4B,EAAOuE,KA2BlB,EAEMC,kBAAoBvG,MAAO0C,EAAcvC,EAAW6B,EAAWE,EAAQsE,KACnEvG,EAAO,CACTgC,WAAYD,EACZS,cAAeC,EACfP,QAASD,EACTuE,UAAWD,CACf,EAEA,OADAxF,MAAMjB,eAAeE,EAAM,cAAeE,CAAS,EAC5C,CACHuG,QAAS,CAAA,CACb,CACJ,EAEMC,kBAAoB3G,UACtB,IACI,IACMC,EAAOe,MADDA,MAAMC,MAAM,yDAAyD,GAC1DK,KAAK,EAE5B,OAAkB,EAAdrB,EAAK2G,QAAc3G,EAAK,GAAG4G,UAC3BhE,aAAaqC,QAAQ,sBAAuBjF,EAAK,GAAG4G,QAAQ,EACrD5G,EAAK,GAAG4G,UAGZ,IAGX,CAFE,MAAOC,GACL,OAAO,IACX,CACJ,EAGA9G,eAAe+G,iBAAiBnF,EAAwBkC,GACvD,IAAM/B,EAASf,MAAMW,wBAAwBC,CAAsB,EAO7DoF,GALNnE,aAAaqC,QAAQ,gBAAiBnD,EAAOK,KAAK,EAClDS,aAAaqC,QAAQ,qBAAsBnD,EAAOC,SAAS,EAC3Da,aAAaqC,QAAQ,kBAAmBnD,EAAOG,MAAM,EAG9BW,aAAaC,QAAQ,sBAAsB,GAClE,GAAI,CAACkE,EAAgB,MAAM,IAAI3G,MAAM,sBAAsB,EAE3DM,IAAIsG,EACJ,IACCA,EAAcC,KAAKC,MAAMH,CAAc,CAGxC,CAFE,MAAOlG,GACR,MAAM,IAAIT,MAAM,2BAA2B,CAC5C,CAGMmC,EAAc,CACnBQ,UAAWiE,EAAYG,cAAgB,WACvClE,gBAAiB+D,EAAYI,aAAe,GAC5CC,aAAcL,EACdvE,aAAcoB,EAAOpB,aACrBE,UAAWkB,EAAOlB,UAClBzC,UAAW2D,EAAO3D,UAClBiD,SAAU8D,KAAKK,UAAUN,CAAW,CACrC,EAGMO,EAAcxG,MAAMyG,iBAAiB1F,EAAOC,UAAWQ,CAAW,EAKxE,OAHAK,aAAaoC,WAAW,sBAAsB,EAGvCuC,CACR,CAEAxH,eAAe0H,oBAAoB5D,EAAQsB,EAAOuC,GAC9C,IACU3F,EADV,GAAmB,EAAfoD,EAAMwB,OAMN,OALM5E,EAAYa,aAAaC,QAAQ,oBAAoB,EAKpD,CACHkD,SALahF,MAAM+E,wBAAwB/D,EAAW8B,EAAO3D,UAAW2D,EAAOpB,YAAY,EAM3F4D,MALUtF,MAAMqF,eAAerE,EAAW8B,EAAOpB,aAAcoB,EAAO3D,SAAS,EAMxF0F,WALiBT,EAAMwC,KAAKC,GAAQ,CAACA,EAAKvE,QAAW,CAACqE,CAAmB,GAKlD9B,UAClB,CAER,CAEA7F,eAAe8H,eAAehE,GAC5B,IAAM9B,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDiF,EAAgBlF,aAAaC,QAAQ,iBAAiB,EAC5D,GAAGiF,EAEF,OADc/G,MAAMqF,eAAerE,EAAW8B,EAAOpB,aAAcoB,EAAO3D,UAAW4H,CAAa,GACrF,IAAM,EAEtB,CAEA/H,eAAeyH,iBAAiBzF,EAAWQ,GAC1C,IACC,IAEgBwF,EAFVjG,EAASf,MAAMuB,kBAAkBP,EAAWQ,CAAW,EAQ7D,OAPIT,GAAUA,EAAOuB,QAAUd,EAAYU,kBAC3B8E,4EAAiFC,OAAOC,SAASC,iDAAiDF,OAAOC,SAASC,uBACjLnH,MAAMoH,eAAe,CACpB1F,aAAcF,EAAYE,aAC1BvC,UAAWqC,EAAYrC,SACxB,EAAG4B,EAAOuB,OAAQd,EAAYU,gBAAgB8E,CAAI,GAE5CjG,CAGR,CAFE,MAAO+E,GACR,MAAMA,CACP,CACD,CAEA9G,eAAeoI,eAAetE,EAAQR,EAAQ+E,GAC7C,IAAMrG,EAAYa,aAAaC,QAAQ,oBAAoB,EAC3D,GAAI,CAACd,EAAW,MAAM,IAAI3B,MAAM,YAAY,EAC5C,GAAKyD,EAAOpB,cAAiBoB,EAAO3D,UACpC,OAAaqD,yBAAyBM,EAAO3D,UAAW6B,EAAWsB,EAAQ+E,EAAavE,EAAOpB,YAAY,EAD5D,MAAM,IAAIrC,MAAM,gBAAgB,CAEhF,CAEA,SAASiI,aAAaxE,GACrB,IAGMpB,EACAV,EACAE,EALN,OAAKW,aAAaC,QAAQ,oBAAoB,GAGxCJ,EAAeoB,EAAOpB,aACtBV,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDZ,EAASW,aAAaC,QAAQ,iBAAiB,EAC9CqC,gBAAgBzC,EAAcV,EAAW8B,EAAO3D,UAAW2D,EAAOlB,UAAWV,CAAM,GALlF,EAMT,CAEAlC,eAAeuI,YAAYzE,GAC1B,IAGMpB,EACAV,EAJN,OAAKa,aAAaC,QAAQ,oBAAoB,GAGxCJ,EAAeoB,EAAOpB,aACtBV,EAAYa,aAAaC,QAAQ,oBAAoB,GACzC9B,MAAMmE,gBAAgBzC,EAAcV,EAAW8B,EAAO3D,UAAW2D,EAAOlB,SAAS,GAG/D4F,OAAOlD,GAC7BA,EAAKlC,QACf,GATI,EAYT,CAEA,SAASqF,WAAWC,GAMlB,GAAI,CAACA,EAAS,MAAO,CAAEC,KAAM,GAAIC,KAAM,EAAG,EAC1CjI,IAAIkI,EAQJ,OANCA,EADGH,CAAAA,EAAQI,SAAS,GAAG,GAEbJ,EAAQI,SAAS,GAAG,EACpB,IAAIC,KAAKL,EAAQM,QAAQ,IAAK,GAAG,CAAC,EAElC,IAAID,KAAKL,CAAO,EAEvBO,MAAMJ,EAAQK,QAAQ,CAAC,EAAU,CAAEP,KAAM,GAAIC,KAAM,EAAG,GAGpDO,EAAgBN,EAAQO,kBAAkB,EASzC,CAAET,KA1BM,CACd,UAAW,WAAY,QAAS,QAAS,MAAO,OAChD,OAAQ,SAAU,YAAa,UAAW,WAAY,aAgBnDU,EAAe,IAAIN,KAAKF,EAAQK,QAAQ,EAAoB,IAAhBC,CAAqB,GAEnCG,SAAS,GAE9B,IADDD,EAAaE,QAAQ,EAKlBX,KAHDS,EAAaG,SAAS,EAAEC,SAAS,EAAEC,SAAS,EAAG,GAAG,EAEnD,IADGL,EAAaM,WAAW,EAAEF,SAAS,EAAEC,SAAS,EAAG,GAAG,CAEhD,EACtB,CAEA,SAASE,qBAAqB9F,EAAQR,GACnBT,aAAaC,QAAQ,oBAAoB,EAA3D,IAiBM7C,EAfL,CACC,CACCqD,OAAU,IACVuG,uBAA0B,uGAC1BC,eAAkB,oCACnB,GAUyBlC,KAAK,GAAamC,EAAQzG,SAAWA,CAAM,EACtE,OAAgBlD,KAAAA,IAATH,EAPN,CACCqD,OAAU,KACVuG,uBAA0B,KAC1BC,eAAkB,aACnB,EAGyC7J,CAC3C,CAEA,SAAS+J,uBAAuBC,EAAkBC,GACjD,WAAYD,KAAoBC,IACjC,CAGA,SAASC,aAAaC,GACrB,GAAIA,GAAUA,EAAOC,OAAQ,CAC5B,GAA6B,UAAzB,OAAOD,EAAOC,QAAuBD,EAAOC,OAAOC,EACtD,OAAOF,EAAOC,OAAOC,EACf,GAA6B,UAAzB,OAAOF,EAAOC,OACxB,OAAOD,EAAOC,MAEhB,CACA,OAAO,IACR,CAGA,SAASE,cAAcH,GACtB,GAAIA,EAAQ,CACX,GAAIA,EAAOrH,MAAoC,EAA5BqH,EAAOrH,KAAKyH,KAAK,EAAE5D,OACrC,OAAOwD,EAAOrH,KACR,GAAIqH,EAAOhI,OAAsC,EAA7BgI,EAAOhI,MAAMoI,KAAK,EAAE5D,OAC9C,OAAOwD,EAAOhI,KAEhB,CACA,MAAO,gBACR,CAEA,SAASqI,aAAajI,GACrB,IAAMkI,EAAYlI,EAAYkI,UACxBC,EAAWnI,EAAYmI,SACvBjI,EAAeF,EAAYE,aAC3BvC,EAAYqC,EAAYrC,UACxBqE,EAAUhC,EAAY8E,aAAa9C,SAA6CyD,OAAOC,SAASC,KA4BrG,OA1B0B,GAAyB7D,oBAAoB5B,EAAcvC,EAAWuK,EAAWC,EAAUnG,CAAO,EAC3HoG,KAAK7J,IACL,GAAIA,EAAS2D,cACZmG,SAASC,cAAc,qEAAqE,EAAEC,UAAYC,WAAW,2DAA2D,EAChLH,SAASC,cAAc,4EAA4E,EAAEG,UAAUC,OAAO,QAAQ,EAC9HL,SAASM,eAAe,mCAAmC,EAAEC,MAAM,OAC7D,GAAIrK,EAASiB,UACnBa,aAAaqC,QAAQ,qBAAsBnE,EAASiB,SAAS,EAC7Da,aAAaqC,QAAQ,kBAAmBnE,EAASmB,MAAM,EACvDW,aAAaqC,QAAQ,gBAAiBnE,EAASqB,KAAK,EACpDiJ,WAAW3I,EAAcvC,CAAS,MAC5B,CAAA,GAAIY,EAA6B,YAA7BA,EAASuB,iBAAiCvB,EAAS6D,kBAAuD,EAAnC7D,EAAS6D,iBAAiBgC,QAQ3G,MAAM,IAAIvG,MAAM,kCAAkC,EAPjB,kCAA7BU,EAAS6D,mBACZ7D,EAAS6D,iBAAmB,+DAEM,YAA/B,OAAO0G,GACVA,EAAoBvK,EAAS6D,iBAAkB,QAAQ,CAIzD,CACD,CAAC,EACA2G,MAAMzK,IACN,MAAMA,CACP,CAAC,CAGH,CAEA,SAAS0K,UAAUhJ,GAClB,IAAMkI,EAAYlI,EAAYkI,UACxBe,EAAejJ,EAAYiJ,aAEjC,OAAO,GAAyB3G,iBAAiB4F,EAAWe,CAAY,EACtEb,KAAK7J,IACL,GAAIA,EAASiB,UACZa,aAAaqC,QAAQ,qBAAsBnE,EAASiB,SAAS,EAC7Da,aAAaqC,QAAQ,kBAAmBnE,EAASmB,MAAM,EACvDW,aAAaqC,QAAQ,gBAAiBnE,EAASqB,KAAK,MAC7C,CAAA,GAAIrB,EAA6B,YAA7BA,EAASuB,iBAAiCvB,EAAS6D,kBAAuD,EAAnC7D,EAAS6D,iBAAiBgC,QAK5G,MAAM,IAAIvG,MAAM,kCAAkC,EAJf,YAA/B,OAAOiL,GACVA,EAAoBvK,EAAS6D,iBAAkB,QAAQ,CAIzD,CACD,CAAC,EACA2G,MAAMzK,IACN,MAAMA,CACP,CAAC,CACH,CAEA,SAASuK,WAAW3I,EAAcvC,GACjC,IAAM6B,EAAYa,aAAaC,QAAQ,oBAAoB,EACrDZ,EAASW,aAAaC,QAAQ,iBAAiB,EAC/C0D,EAAWkF,KAAKC,eAAe,EAAEC,gBAAgB,EAAEC,SAEzD,OAAOtF,kBAAkB7D,EAAcvC,EAAW6B,EAAWE,EAAQsE,CAAQ,CAC9E,CAEA,SAASsF,gBAAgBC,GACxB,IACC,IAGMC,EACAC,EAEAC,EAMAC,EAZN,OAAKJ,GAAsB,KAAfA,EAAIvB,KAAK,GAIfyB,GADAD,EAAI,IAAInL,IAAIkL,CAAG,GACJK,KAIO,KAFlBF,EAAWF,EAAEK,SAASC,MAAM,GAAG,EAAE9D,OAAO+D,OAAO,GAExC3F,OACLqF,IAGFE,EAAWD,EAASM,QAAQ,GACzBC,KAAKR,CAAM,EACbE,EAASO,KAAK,KAAK,IAblB,EAgBT,CAFE,MAAO5L,GACR,MAAO,EACR,CAED,CAEA,SAAS6L,gBAAgBC,GACxB,IAOMC,EAAShC,SAASM,eAAe,mBAAmB,EAC1D0B,EAAOC,QAAU,CAAA,EACjBD,EAAOE,iBAAiB,QATH,KACpB,IAAMC,EAAQC,WAAW,KACxBpK,aAAaqC,QAAQ,2BAA4B,GAAG,EACpD0H,EAAYM,KAAK,EACjBC,aAAaH,CAAK,CACnB,EAAG,GAAG,CACP,CAG6C,CAC9C,CAEA,SAASI,8BACR,IACOC,EADHxK,aAAaC,QAAQ,oBAAoB,GAMtCuK,EAAKxC,SAASM,eAAe,8CAA8C,KAC1EkC,EAAGC,MAAMC,QAAU,SANpBF,EAAKxC,SACTM,eAAe,6CAA6C,EAC5DqC,QAAQ,qCAAqC,KACvCH,EAAGC,MAAMC,QAAU,OAK7B,OAKME,uBACFrG,aAAe,GACfE,aAAe,GACfoG,cAAgB,KAChB5J,OAAS,GACT6D,oBAAsB,EACtBgG,0BAA4B,EAC5BC,uBAAyB,EACzBC,aAAe,GACfC,aAAe,GAKfC,YAAYzG,EAAc0G,GACtBC,KAAK3G,aAAeA,GAAgB,GACpC2G,KAAK7G,aAAeE,GAAcF,cAAgB,GAClD6G,KAAKC,KAAKF,CAAI,EACdC,KAAKH,aAAe,CAChBK,kBAAmBC,iBAAiBC,aAAa,mBAAmB,EACpEC,iBAAkBF,iBAAiBC,aAAa,kBAAkB,EAClEE,SAAUH,iBAAiBC,aAAa,UAAU,EAClDG,aAAcJ,iBAAiBC,aAAa,cAAc,EAC1DI,YAAaL,iBAAiBC,aAAa,aAAa,EACxDK,gBAAiBN,iBAAiBC,aAAa,iBAAiB,EAChEM,kBAAmBP,iBAAiBC,aAAa,mBAAmB,EACpEO,iBAAkBR,iBAAiBC,aAAa,kBAAkB,EAClEQ,gBAAiBT,iBAAiBC,aAAa,iBAAiB,EAChES,yBAA0BV,iBAAiBC,aAAa,0BAA0B,EAClFU,WAAYX,iBAAiBC,aAAa,YAAY,EACtDW,eAAgBZ,iBAAiBC,aAAa,gBAAgB,EAC9DY,gBAAiBb,iBAAiBC,aAAa,iBAAiB,EAChEa,cAAed,iBAAiBC,aAAa,eAAe,CAChE,EACAJ,KAAKkB,aAAe,IAAIC,aAAanB,KAAKoB,UAAU,CACxD,CAKAnB,WAAWF,GACPC,KAAKnK,OAASmK,KAAKqB,UAAU,EAG7B,IAAMC,EAAY,IAAIC,gBAAgBvH,OAAOC,SAASuH,MAAM,EACtDC,EAAaH,EAAUI,IAAI,0BAA0B,EAC3D,GAAID,EACA,IAEI,IAAMlI,EAAcxG,MAAM+F,iBAAiB2I,EAAYzB,KAAKnK,MAAM,EAQ5D8L,GAPN3B,KAAKJ,aAAe7M,MAAMuH,YAAY0F,KAAKnK,MAAM,EAEjDmK,KAAKtG,oBAAsBH,EAAYlE,OAEvCuM,yBAAyB,EADzB7B,EAAO,iBACuB,EAE9BuB,EAAUO,OAAO,0BAA0B,EAC5B7H,OAAOC,SAASmE,UAAYkD,EAAU9F,SAAS,EAAI,IAAM8F,EAAU9F,SAAS,EAAI,KAC/FxB,OAAO8H,QAAQC,aAAa,GAAInF,SAASoF,MAAOL,CAAM,CAG1D,CAFE,MAAO9I,GACLmH,KAAKiC,wBAAwB,2BAA6BpJ,EAAI1F,QAAS,OAAO,CAClF,KACG,CAEG+O,EAAiBtN,aAAaC,QAAQ,0BAA0B,GAClEqN,CAAAA,GAAmBlC,KAAK7G,eAAkB+I,IAC1ClC,KAAKJ,aAAe7M,MAAMuH,YAAY0F,KAAKnK,MAAM,EAEzD,CAGAnD,IAAIyP,EAEAC,6BAA6B,EAC7BD,EAAyB,CAAA,EAEZ,gBAATpC,IACAoC,EAAyBpP,MAAMsP,gCAC3BrC,KAAKJ,aACLI,KAAKnK,MACT,GAGRyM,2BAA2BtC,KAAKJ,YAAY,EAEvC2C,wBAAwB,GACzBX,yBAAyB,CAAA,CAAI,EAG7BO,GAEAP,yBAAyB,CAAA,CAAK,EAElC5B,KAAKP,cAAgB1M,MAAMiN,KAAKwC,oBAAoBzC,CAAI,EACxDC,KAAKyC,4BAA4B,CACrC,CAEApB,YACI,IAAMqB,EAAS9F,SAASC,cAAc,uCAAuC,EAC7E,GAAK,CAAE6F,GAAU,CAAEA,EAAOC,IACtB,MAAM,IAAIvQ,MAAM,qBAAqB,EAGnC0L,EAAM,IAAIlL,IAAI8P,EAAOC,GAAG,EAC1B9M,EAAS+M,OAAOC,YAAY/E,EAAIgF,aAAaC,QAAQ,CAAC,EAC1D,GAAK,CAAElN,EACH,MAAM,IAAIzD,MAAM,4BAA4B,EAEhD,GAAOyD,EAAOpB,cAAkBoB,EAAO3D,WAAe2D,EAAOlB,UAI7D,OAAOkB,EAHH,MAAM,IAAIzD,MAAM,sCAAsC,CAI9D,CAKA4Q,uBACI,IAAMC,EAAerG,SAASM,eAAe,mCAAmC,EAE5E+F,GACAA,EAAanE,iBAAiB,QAAS/M,UAEnC,IAAMmR,EAAmBtG,SAASM,eAAe,2BAA2B,EACtEnI,EAAYmO,EAAiBC,MACnC,GAAOpO,EAAP,CAQA,IAAMqO,EAAyBxG,SAASM,eAAe,iCAAiC,EAClFjI,EAAkBmO,EAAuBD,MAC/C,GAAOlO,EAAP,CAUAvC,IAAIgK,EAAW,GACXD,EAAY,GACZe,EAAe,GACnB,IAAM6F,EAAsBzG,SAASC,cAAc,4BAA4B,EAE/E,GAAKwG,GAAuBA,EAAoBrG,UAAUsG,SAAS,QAAQ,EAAI,CAC3E,IAAMC,EAAmB3G,SAASM,eAAe,gCAAgC,EACjF,IAAMsG,EAAkB5G,SAASM,eAAe,+BAA+B,EACzEuG,EAAsB7G,SAASM,eAAe,mCAAmC,EAGvF,GAAK,EADLT,EAAY8G,EAAiBJ,OAOzB,OALAI,EAAiBlE,MAAMqE,YAAc,MACrCH,EAAiBpG,MAAM,EADvBoG,KAEAA,EAAiBzE,iBAAiB,QAAS,WACvCkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,EAKL,GAAKH,GAAoBC,GAEhB,EADL9G,EAAW8G,EAAgBL,OAOvB,OALAK,EAAgBnE,MAAMqE,YAAc,MACpCF,EAAgBrG,MAAM,EADtBqG,KAEAA,EAAgB1E,iBAAiB,QAAS,WACtCkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,EAMT,GAAKH,GAAoBE,GAAuB,CAAED,GAEzC,EADLhG,EAAeiG,EAAoBN,OAO/B,OALAM,EAAoBpE,MAAMqE,YAAc,MACxCD,EAAoBtG,MAAM,EAD1BsG,KAEAA,EAAoB3E,iBAAiB,QAAS,WAC1CkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,CAKb,CAGA,IAAMH,EAAmB3G,SAASM,eAAe,gCAAgC,EACjFT,EAAY8G,EAAiBJ,MAGvBF,EAAerG,SAASM,eAAe,mCAAmC,EAI5E3I,GAHJ0O,EAAaU,SAAW,CAAA,EACxBV,EAAanG,UAAYC,WAAW,kBAAkB,EAEpC,CACdhI,UAAWA,EACXE,gBAAiBA,EAEjBoE,aAAc2G,KAAK3G,aACnB5E,aAAcuL,KAAKnK,OAAOpB,aAC1BE,UAAWqL,KAAKnK,OAAOlB,UACvBzC,UAAW8N,KAAKnK,OAAO3D,UACvBiD,SAAU8D,KAAKK,UAAU0G,KAAK3G,cAAmC,CAAC9C,QAAQ,mBAAmB,CAAC,CAClG,GAEKkG,IACDlI,EAAYkI,UAAYA,GAEvBC,IACDnI,EAAYmI,SAAWA,GAEtBc,IACDjJ,EAAYiJ,aAAeA,GAI/B5I,aAAaqC,QAAQ,uBAAwBgC,KAAKK,UAAU,CACxD,GAAG0G,KAAK3G,aACRD,YAAanE,CACjB,CAAC,CAAC,EAEFvC,IAAIkR,EACJ,IACIA,EAAmB7Q,MAAMiN,KAAK6D,WAAWtP,CAAW,CAIxD,CAHE,MAAO1B,GAEL,OADAmN,KAAAA,KAAKiC,wBAAwBpP,EAAMM,OAAO,CAE9C,CAGA8P,EAAaU,SAAW,CAAA,EACxBV,EAAa5D,MAAMyE,OAAS,UAEvBF,EAAiBG,cAKa5R,KAAAA,IAA9ByR,EAAiBI,WAClBhE,KAAK3G,aAAa2K,SAAWJ,EAAiBI,UAIlDhE,KAAKJ,aAAe7M,MAAMuH,YAAY0F,KAAKnK,MAAM,EAEjDyM,2BAA2BtC,KAAKJ,YAAY,EAE5CI,KAAK3G,aAAe,GACpBtG,MAAMiN,KAAKwC,oBAAoB,YAAY,EAC3CZ,yBAAyB,CAAA,CAAK,EAC9BqC,sBAAsB,CAAA,CAAK,EApH3B,MANIb,EAAuB/D,MAAMqE,YAAc,MAC3CN,EAAuBjG,MAAM,EAC7BiG,EAAuBtE,iBAAiB,QAAS,WAC7CkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,CARL,MANIR,EAAiB7D,MAAMqE,YAAc,MACrCR,EAAiB/F,MAAM,EACvB+F,EAAiBpE,iBAAiB,QAAS,WACvCkB,KAAKX,MAAMqE,YAAc,EAC7B,CAAC,CAiIT,CAAC,CAET,CAMAlB,0BAA0BzC,EAAMmE,EAAsB,CAAA,GAClD,IAAMC,EAAkBvH,SAASC,cAAc,sBAAsB,EAAID,SAASC,cAAc,sBAAsB,EAAID,SAASwH,cAAc,KAAK,EACtJD,EAAgBE,UAAY,sBAC5BF,EAAgBG,UAAYvH,WAAW,EAAE,EACzCoH,EAAgBI,gBAAgB,OAAO,EAEvC7R,IAAI8R,EAAe,GACfC,EAEAC,EAAoB,GAExB,OAAQ3E,GACJ,IAAK,eACDyE,EAAe,eACfxE,KAAK2E,UAAYH,EACjBE,EAAoB,CAChBvL,aAAc6G,KAAK7G,aACnByL,cAAehI,SAAS3C,SAAS4K,UAAY,GAC7C3E,kBAAmBC,iBAAiBC,aAAa,mBAAmB,EACpEG,aAAcJ,iBAAiBC,aAAa,cAAc,EAC1DC,iBAAkBF,iBAAiBC,aAAa,kBAAkB,EAClE,GAAGJ,KAAKH,YACZ,EACAiF,wBAAwB,GAAKlD,yBAAyB,CAAA,CAAK,EAC3D,MACJ,IAAK,OACD,GAAImD,yBAAyB,EACzB,OAEJP,EAAe,OACfE,EAAoB,CAAC,GAAG1E,KAAKH,YAAY,EACzC,MACJ,IAAK,cACD2E,EAAe,cACfE,EAAoB,CAAC,GAAG1E,KAAKH,YAAY,EACzC,MACJ,IAAK,aACD2E,EAAe,aACfxE,KAAK2E,UAAYH,EACjBE,EAAoB,CAAC,GAAG1E,KAAKH,YAAY,EACzC,MACJ,IAAK,YACD2E,EAAe,YACf,IAAMQ,EAAgBpQ,aAAaC,QAAQ,qBAAqB,EAChE6P,EAAoB,CAChBO,eAAgBD,EAAgB,mBAAqBA,EAAgB,IAAM,GAC3E5I,OAAQ+D,iBAAiBC,aAAa,YAAY,EAClD8E,QAAS/E,iBAAiBC,aAAa,SAAS,EAChD+E,SAAUhF,iBAAiBC,aAAa,UAAU,EAClDgF,gBAAiBjF,iBAAiBC,aAAa,iBAAiB,EAChEF,kBAAmBC,iBAAiBC,aAAa,mBAAmB,EACpE1D,SAAU,QACVvI,MAAO,GACP,GAAG6L,KAAKH,YAAY,EACxB,MACJ,IAAK,iBACD2E,EAAe,iBACfxE,KAAK2E,UAAYH,EAEjBxE,KAAKL,uBAAyB0F,MAAMC,QAAQtF,KAAKJ,YAAY,EAAII,KAAKJ,aAAajH,OAAS,EAE5FqH,KAAKN,0BAA4B2F,MAAMC,QAAQtF,KAAKJ,YAAY,EAC1DI,KAAKJ,aAAarF,OAAOlD,IACvB,IAEI,OADaA,EAAKlC,SAAW8D,KAAKC,MAAM7B,EAAKlC,QAAQ,EAAI,IAC7CoB,UAAYyD,OAAOC,SAASC,IAChB,CAA1B,MAAOqL,GAAK,MAAO,CAAA,CAAO,CAChC,CAAC,EAAE5M,OACD,EAEN+L,EAAoB,CAChBxM,WAAY,MACZsN,cAAe,GACfC,cAAe1J,uBAAuBiE,KAAKN,0BAA2BM,KAAKL,sBAAsB,EACjG,GAAGK,KAAKH,YACZ,CAIR,CACAsE,EAAgBG,UAAYtE,KAAK0F,aAAalB,EAAcE,CAAiB,EAC7E9H,SAAS3J,KAAK0S,YAAYxB,CAAe,EAGzCyB,wBAAwB,EACxB,IAAMC,EAAYjJ,SAASC,cAAc,gCAAgC,EACzE,OAAQkD,GACJ,IAAK,eAEE8F,GAAa,CAACjR,aAAaC,QAAQ,UAAU,EAC5CgR,EAAU7I,UAAU8I,IAAI,wCAAwC,EAC1DD,GACNA,EAAU7I,UAAUC,OAAO,wCAAwC,EAGvE,IAAM8I,EAAY/L,OAAOgM,aAAa,EAChCC,EAAkB,CAAC,CAACrR,aAAaC,QAAQ,oBAAoB,EAC7DV,EAAQS,aAAaC,QAAQ,eAAe,EAE9CoR,GAAmB9R,GAAS,CAACA,EAAM0G,SAAS,UAAU,GACtD+B,SAASC,cAAc,4BAA4B,EAAEG,UAAU8I,IAAI,QAAQ,EAGxD,UAAnBC,EAAUhG,OAGVmG,wBADqBC,uBAAuBJ,CAAS,EAChBK,QAAQ,EAC7CpG,KAAKqG,wBAAwB,GAGjCrG,KAAKgD,qBAAqB,EAC1B,MACJ,IAAK,OACDjQ,MAAMiN,KAAKsG,aAAa,EACxB1J,SAASC,cAAc,2BAA2B,EAAEiC,iBAAiB,QAAS,IACpEyH,EAAuBhB,EAAEiB,cAAcxJ,UACzCuJ,GAAwB,CAACA,EAAqBjD,SAAS,QAAQ,GAC/DtD,KAAKwC,oBAAoB,YAAY,CAE7C,CAAC,EACDyB,sBAAsB,CAAA,CAAK,EAC3B,MACJ,IAAK,cACDrH,SAASC,cAAc,6BAA6B,EAAEiC,iBAAiB,QAAS,IAC5E2H,kBAAkBzG,KAAK3G,aAAc,cAAc,CACvD,CAAC,EACD,MACJ,IAAK,aACMwM,GAAa,CAACjR,aAAaC,QAAQ,UAAU,EAC5CgR,EAAU7I,UAAU8I,IAAI,wCAAwC,EAC1DD,GACNA,EAAU7I,UAAUC,OAAO,wCAAwC,EAGvE2I,wBAAwB,EAC5BlT,IAAIgU,EAAuB,EACtB1G,KAAKJ,cAAcjH,SACpBqH,KAAKJ,aAAe7M,MAAMuH,YAAY0F,KAAKnK,MAAM,GAErD,IAAMsB,EAAQ6I,KAAKJ,aAEf+G,GADJlC,EAAmB1R,MAAM0G,oBAAoBuG,KAAKnK,OAAQsB,EAAO6I,KAAKtG,mBAAmB,EAC9D,IAC3B,GAAmB,EAAfvC,EAAMwB,OAAY,CAClB,IAAMiO,EAAa5M,OAAOC,SAASC,KACnC,IAAM2M,EAAc1P,EAAM2P,KAAK,CAACC,EAAGC,KACzBC,EAAUhO,KAAKC,MAAM6N,EAAE5R,QAAQ,EAAEoB,UAAYqQ,EAAa,EAAI,EAEpE,OADgB3N,KAAKC,MAAM8N,EAAE7R,QAAQ,EAAEoB,UAAYqQ,EAAa,EAAI,GACnDK,CACrB,CAAC,EAEDrK,SAASC,cAAc,2CAA2C,EAAEyH,UAAY,GAEhF,IAAK5R,IAAIwU,EAAI,EAAGA,EAAIL,EAAYlO,OAAQuO,CAAC,GAAI,CACzC,IAAMC,EAASN,EAAYK,GAGrB7R,EAAS8R,EAAO9R,OAChBN,EAAYoS,EAAOpS,UACnBqS,EAAiBD,EAAOhS,SAC9BzC,IAAI2U,EAAW,KACf,GAAID,EACA,KACIC,EAAWpO,KAAKC,MAAMkO,CAAc,GAC3BE,QAAgC,SAAtBH,EAAOvP,WAC1ByP,EAAShS,OAAS8R,EAAO9R,MAG7B,CAFE,MAAOxC,GACLwU,EAAW,IACf,CAEJ,IAsBUE,EAEAC,EAxBJC,EAAiBJ,EAAWA,EAAS9Q,QAAU,GAC/CmR,EAAeL,EAAWA,EAASjB,SAAW,GAGpD1T,IAAIiV,EAAyB,GACzBC,EAAuB,4BACvBP,GAAkClV,KAAAA,IAAtBkV,EAASrD,WAGjB4D,EAFAP,EAASrD,UACT2D,EAAyB3H,KAAKH,aAAakB,eACpB,uBAEvB4G,EAAyB3H,KAAKH,aAAamB,gBACpB,sEAI5ByG,IAAmBzN,OAAOC,SAASC,MAClCwM,CAAoB,GAGnBxC,GAAuBuD,IAAmBzN,OAAOC,SAASC,OAIrDsN,EAAaK,cAFbN,EAAkBO,mBAAmBrD,EAAkBpP,CAAM,CAEnB,EAC1C0S,EAA8B,CAChChT,UAAWA,GAAa,GACxB6G,uBAAwB2L,EAAgB3L,uBACxCC,eAAgB0L,EAAgB1L,eAChC8L,uBAAwBA,EACxBC,qBAAsBA,EACtBI,gBAAiBjL,WAAWwK,EAAgBU,eAAe,EAC3DC,YAAaT,EACbxG,cAAejB,KAAKH,aAAaoB,cACjCkH,qBAAsBtK,gBAAgB4J,CAAc,EACpDnQ,eAAgBiQ,EAAgBa,gBAChChC,SAAUpG,KAAKqI,iBAAiBX,CAAY,EAC5CrS,OAAQA,EACRiT,eAAgBd,EAAWc,eAC3BC,YAAaf,EAAWe,YACxBC,mBAAoBhB,EAAWgB,mBAC/BC,cAAejB,EAAWiB,cAC1BC,YAAa,GACbC,kBAAyC,SAAtBxB,EAAOvP,WAAwB,GAAK,qCACvDgR,gBAAuC,SAAtBzB,EAAOvP,WAAwB,GAAKoI,KAAK0F,aAAa,WAAW,CACtF,EAE+BmD,oCAAoCtB,EAAgBlS,MAAM,IAErF0S,EAA4BW,YAAc,UAE9C9L,SAASC,cAAc,2CAA2C,EAAEyH,WAAatE,KAAK0F,aAAa,cAAeqC,CAA2B,EAExI/H,KAAK8I,0BAA0BzB,CAAQ,GACxCV,EAAqBnI,KAAK6I,CAAQ,EAG9C,CACArH,KAAKN,0BAA4BgH,EACjC1G,KAAKL,uBAAyBxI,EAAMwB,OACpCoQ,yBAAyBpC,EAAsB3G,IAAI,EACnDpD,SAASC,cAAc,kCAAkC,EAAEyH,WAAavH,WAAW,IAAMhB,uBAAuBiE,KAAKN,0BAA2BM,KAAKL,sBAAsB,CAAC,CAChL,CAEqB,IAAjBxI,EAAMwB,SACNiE,SAASC,cAAc,2CAA2C,EAAEyH,UAAYvH,WAAW,mFAAmF,GAIlLiD,KAAKgJ,gBAAgB,EACrB/E,sBAAsB,CAAA,CAAK,EAC3B,MACR,IAAK,YAEGvF,gBAAgBsB,IAAI,EACpBb,4BAA4B,EAEtB8J,EAAOlW,MAAM8G,eAAemG,KAAKnK,MAAM,EACvCqT,EAAmBnW,MAAM2F,kBAAkB,EAE3CyQ,EAAUvU,aAAaC,QAAQ,qBAAqB,GAAKqU,EAG/DxE,EAAkBO,gBAFDkE,qBAA6BA,KAAa,KAEN,GAElDF,IACCvE,EAAkBhI,SAAWuM,EAAKnU,MAAQ,QAC1C4P,EAAkBvQ,MAAQ8U,EAAK9U,OAAS,GACrC8U,GAAM7M,QAAQgN,KAAG1E,EAAkBtI,OAAS6M,GAAM7M,QAAQgN,GAGjEjF,EAAgBG,UAAYtE,KAAK0F,aAAa,YAAahB,CAAiB,EAC5E9H,SAAS3J,KAAK0S,YAAYxB,CAAe,EACzCzF,gBAAgBsB,IAAI,EACpBb,4BAA4B,EAE5B,MACR,IAAK,iBACE0G,GAAa,CAACjR,aAAaC,QAAQ,UAAU,EAC5CgR,EAAU7I,UAAU8I,IAAI,wCAAwC,EAC1DD,GACNA,EAAU7I,UAAUC,OAAO,wCAAwC,EAGnE,IAAM1I,EAAcxB,MAAM+U,mBAD1BrD,EAAmB1R,MAAM0G,oBAAoBuG,KAAKnK,OAAQmK,KAAKJ,aAAcI,KAAKtG,mBAAmB,EACtCsG,KAAKtG,mBAAmB,EAEjF2P,EAAoBzM,SAASC,cAAc,kCAAkC,EAC/EwM,IACAA,EAAkBvM,UAAYC,WAAWxI,EAAY2D,UAAU,GAGnEwM,EAAkBxM,WAAa3D,GAAa2D,WAC5CwM,EAAkBc,cAAgBjR,GAAaiR,cAI/C9S,IAAI0T,EAAW,KACLkD,EAAkBtJ,KAAKJ,aAAajG,KAAK,GAAa4P,OAAOzN,EAAQzG,MAAM,IAAMkU,OAAOhV,EAAYc,MAAM,CAAC,EACjH3C,IAAIwC,EAAO,KAEX,GAAIoU,GAAmBA,EAAgBnU,SACnC,IACID,EAAO+D,KAAKC,MAAMoQ,EAAgBnU,QAAQ,EAC1CiR,EAAWlR,EAAKkR,UAAY,IACY,CAA1C,MAAOb,GAAKa,EAAW,KAAMlR,EAAO,IAAM,CAGxDwP,EAAkBwD,YAAchT,EAAKqB,QACrC,IAAM4R,EAAuBjT,EAAKqB,QAAQwE,QAAQf,OAAOC,SAASuP,OAAQ,EAAE,EAmBlEC,GAlBV/E,EAAkByD,qBAAuBA,EAAqBxP,OAAS,EACjEzD,EAAKqB,QAAQwE,QAAQf,OAAOC,SAASyP,SAAW,IAAK,EAAE,EAAIvB,EACjEzD,EAAkBiF,gBAAkB,CAAC/U,aAAaC,QAAQ,UAAU,EAC9D,uEAAyE,gCAC/EsP,EAAgBG,UAAYtE,KAAK0F,aAAa,iBAAkBhB,CAAiB,EACjF9H,SAAS3J,KAAK0S,YAAYxB,CAAe,EAGjCyB,wBAAwB,EAEpB1Q,GAAQkR,IAER2C,yBAAyB,CAAC7T,GAAO8K,IAAI,EACE,YAAnC,OAAOkG,0BACPA,wBAAwBE,CAAQ,EAIZxJ,SAASC,cAAc,gDAAgD,GACnG+M,EAAkB,GAChBC,EAAejV,aAAaC,QAAQ,iBAAiB,EAE3D,GAAwC,EAAnCN,EAAYiR,cAAc7M,OAAa,CACxCmR,mCAAmCvV,EAAYc,MAAM,EACrDoU,EAAwBnF,UAAYvH,WAAW,EAAE,EACjD,IAAK,IAAM/H,KAAWT,EAAYiR,cAAe,CAE7C,IADAuE,EAAeC,OAAOH,CAAY,IAAMG,OAAOhV,EAAQiV,aAAa,EAC9DzC,EAAaK,cAAc,CAC7BjM,uBAAwB5G,EAAQkV,uBAChCrO,eAAgB7G,EAAQmV,iBAC5B,CAAC,EACKC,EAAc,CAChBD,kBAAmBnV,EAAQmV,kBAC3BnS,YAAahD,EAAQgD,YACrBC,YAAajD,EAAQiD,YACrBoS,YAAarV,EAAQqV,YACrBnS,WAAYwM,EAAkBxM,WAC9BoQ,eAAgBd,EAAWc,eAC3BC,YAAaf,EAAWe,YACxBC,mBAAoBhB,EAAWgB,mBAC/BC,cAAejB,EAAWiB,cAC1B6B,uBAAwBP,EAAe,QAAU,OACrD,EAC6C5X,KAAAA,IAAzCyX,EAAgB5U,EAAQiD,eACxB2R,EAAgB5U,EAAQiD,aAAe,IAGvC2R,EAAgB5U,EAAQiD,aAAauG,KAAK4L,CAAW,CAE7D,CACA1X,IAAI6X,EAAkB,GAEtB,IAAK,IAAMC,KAAOZ,EAAiB,CAC/BlX,IAGW+X,EAHPC,EAAqBd,EAAgBY,GACzC9X,IAAIiY,EAAyB,GAE7B,IAAWF,KADXC,EAAmB5D,KAAK,CAACC,EAAGC,IAAMD,EAAEsD,YAAYO,cAAc5D,EAAEqD,WAAW,CAAC,EACpDK,EAAoB,CACxChY,IAAImY,EAAkCH,EAAmBD,GACzDE,GAA0B3K,KAAK0F,aAAa,0BAA2BmF,CAA+B,CAC1G,CACAN,GAAmBvK,KAAK0F,aAAa,6BACjC,CACIoF,mBAAoBN,EACpBO,mBAAoBJ,EACpB/B,gBAAkD,SAAjCnE,GAAkB7M,WAAwB,GAAKoI,KAAK0F,aAAa,eAAe,CACrG,CACJ,CACJ,CACA+D,EAAwBnF,UAAYiG,CACxC,MACId,EAAwBnF,UAAYvH,WAAW,aAAa,EAI1DiO,EAAWpO,SAASC,cAAc,yCAAyC,EAE7E,SAASoO,IACgB,GAEjBjL,KAAKmD,MAAMxK,OACXqH,KAAKhD,UAAU8I,IAAI,MAAM,EAEzB9F,KAAKhD,UAAUC,OAAO,MAAM,CAEpC,CATA+N,IAUAA,EAASlM,iBAAiB,QAASmM,CAAoB,EACvDD,EAASlM,iBAAiB,SAAUmM,CAAoB,GAI5DhH,sBAAsB,EAGtBjF,WAAW,KACP,IAAMkM,EAAmBtO,SAASC,cAAc,8BAA8B,EAC9EqO,EAAiBC,SAAS,CACtBC,IAAKF,EAAiBG,aACtBC,SAAU,QACd,CAAC,CACL,EAAG,CAAC,EAEJ,IAAMC,EAAa3O,SAASC,cAAc,0CAA0C,EACpF,GAAI0O,EAAY,CACZvL,KAAKkB,aAAajB,KAAK,EACvBvN,IAAI8Y,EAAcxL,KAClBuL,EAAWzM,iBAAiB,QAAS/M,MAAOwT,IACxCA,EAAEkG,eAAe,EAEjB,IACMC,EADuBH,EAAWhM,QAAQ,mCAAmC,EAChD1C,cAAc,yCAAyC,EAEpFzC,EAAcsR,EAAMvI,MAAM5G,KAAK,EACrC,GAAKnC,EAAL,CAIAsR,EAAM/H,SAAW,CAAA,EACjB4H,EAAW5H,SAAW,CAAA,EAEtBjR,IAAIiZ,EAAqB,KAEzB,IACIA,EAAqB5Y,MAAMoH,eAAe6F,KAAKnK,OAAQmK,KAAKtG,oBAAqBU,CAAW,EAC5FsR,EAAMvI,MAAQ,GACdpQ,MAAMiN,KAAKwC,oBAAoB,gBAAgB,EAC/CyB,sBAAsB,CAAA,CAAK,CAG/B,CAFE,MAAOpL,GACL+S,MAAM,gCAAkC/S,EAAI1F,OAAO,CACvD,CAEIqY,EAAYtK,aAAa2K,SAAS,GAA4B,OAAvBF,GAA+BA,EAAmBnZ,eAAe,WAAW,IAC7GuB,EAAYa,aAAaC,QAAQ,oBAAoB,GACrDiX,EAAwB/Y,MAAMyY,EAAYtK,aAAa6K,0BAA0BP,EAAY3V,OAAQ9B,EAAW4X,EAAmBlW,SAAS,GACvHgD,UACvB+S,EAAYtK,aAAa8K,UAAU,uDAAuD,EACpFC,EAAYhT,KAAKK,UAAUwS,CAAqB,EACtDI,QAAQC,IAAIF,CAAS,IAI7BP,EAAM/H,SAAW,CAAA,EACjB4H,EAAW5H,SAAW,CAAA,CA7BE,CA8B5B,CAAC,CACL,CAMR,CAEMyI,EAA4BxP,SAASC,cAAc,oCAAoC,EAC7F,IAAM2O,EAAcxL,KACfoM,GACDA,EAA0BtN,iBAAiB,QAAS,SAASyG,EAAG8G,EAAOb,GACnEa,EAAK7J,oBAAoB,YAAY,CACzC,CAAC,EAGC8J,EAAsB1P,SAASC,cAAc,6CAA6C,EA+ChG,OA9CKyP,GACDtM,KAAKkB,aAAaqL,oBAAoBD,CAAmB,EAG7D1P,SAASC,cAAc,gCAAgC,GAAGiC,iBAAiB,QAAS,IAChFkB,KAAKf,KAAK,CACd,CAAC,EAEDrC,SAASC,cAAc,qBAAqB,GAAGiC,iBAAiB,QAAS,KACrEkB,KAAKwC,oBAAoB,WAAW,CACxC,CAAC,EAED5F,SAASC,cAAc,8CAA8C,GAAGiC,iBAAiB,QAAS,KAC9F/H,kBAAkBiJ,KAAKnK,OAAO3D,SAAS,CAC3C,CAAC,EAED0K,SAASM,eAAe,kBAAkB,GAAG4B,iBAAiB,QAAS,KACnE0N,kBAAkB,CACtB,CAAC,EAED5P,SAASM,eAAe,yBAAyB,GAAG4B,iBAAiB,QAAS,KAC1E,IAAM+G,EAAYjJ,SAASC,cAAc,gCAAgC,EAEtE,CAACjI,aAAaC,QAAQ,UAAU,GAAKgR,EAAU7I,UAAUsG,SAAS,wCAAwC,GACzG1O,aAAaqC,QAAQ,WAAY,GAAG,EACpC4O,EAAU7I,UAAUC,OAAO,wCAAwC,IAEnErI,aAAaqC,QAAQ,WAAY,GAAG,EACpC4O,EAAU7I,UAAU8I,IAAI,wCAAwC,EAExE,CAAC,EAEDlJ,SAASC,cAAc,+CAA+C,GAAGiC,iBAAiB,QAAS,KAC/F0N,kBAAkB,CACtB,CAAC,EAED5P,SAASC,cAAc,sBAAsB,GAAGiC,iBAAiB,QAAS,KACtEkB,KAAKwC,oBAAoBxC,KAAK2E,SAAS,CAC3C,CAAC,EAQMR,CACX,CAEA6E,kBACIpM,SAAS6P,iBAAiB,aAAa,EAAEC,QAAQ9S,IAC7CA,EAAKkF,iBAAiB,QAAS/M,UAC3BW,IAAI0T,EAAW,KACf,IACIA,EAAWnN,KAAKC,MAAMU,EAAK+S,aAAa,gBAAgB,CAAC,CAG7D,CAFE,MAAO9Z,GACLuT,EAAW,IACf,CACIA,GACAF,wBAAwBE,CAAQ,EAEpCpG,KAAKtG,oBAAsBE,EAAK+S,aAAa,cAAc,EAC3D5Z,MAAMiN,KAAK4M,YAAY,CAC3B,CAAC,CACL,CAAC,CACL,CAQAA,oBACI7Z,MAAMiN,KAAKwC,oBAAoB,gBAAgB,EAC/C,IAAMqK,EAAoB7M,KAAK8M,qBAAqB9M,KAAKtG,mBAAmB,EAExEmT,IACAjH,wBAAwB,EACxBmD,yBAAyB,CAAC8D,GAAoB7M,IAAI,EAClDA,KAAKqG,wBAAwB,GAGjCpC,sBAAsB,CAAA,CAAK,CAC/B,CAWAyB,aAAalB,EAAcuI,EAAY,IACnCra,IAAIsa,EAAWC,uBAAuBC,gBAAgB1I,CAAY,EAElE,IAAK,GAAM,CAACnS,EAAK8Q,KAAUP,OAAOG,QAAQgK,CAAS,EAAG,CAC5CI,OAAmB9a,MACzBK,IAAI0a,EAOAA,EAFApN,KAAKqN,yBAAyBL,EAAUG,CAAW,EAErCnN,KAAKoB,WAAWmI,OAAOpG,CAAK,CAAC,EAG7BpG,WAAWwM,OAAOpG,CAAK,EAAG,CAAC6J,SAAUxI,EAAc8I,UAAW,CAAA,CAAI,CAAC,EAGrFN,EAAWA,EAASO,WAAWJ,EAAaC,CAAW,CAC3D,CAEA,OAAOrQ,WAAWiQ,EAAU,CAACA,SAAUxI,CAAY,CAAC,CACxD,CAQA6I,yBAAyBL,EAAUG,GAEzBK,EAAqBL,EAAYpS,QAAQ,QAAS,MAAM,EAY9D,OAPyB,IAAI0S,oCACID,cAC7B,GACJ,EAIwBE,KAAKV,CAAQ,CACzC,CAEA5L,WAAa,GACFuM,EACF5S,QAAQ,KAAM,OAAO,EACrBA,QAAQ,KAAM,MAAM,EACpBA,QAAQ,KAAM,MAAM,EACpBA,QAAQ,KAAM,QAAQ,EACtBA,QAAQ,KAAM,QAAQ,EAG/BuL,qBACI,GAAI,CAAC1R,aAAaC,QAAQ,oBAAoB,EAC1C,MAAO,GAGX,IAAMJ,EAAeuL,KAAKnK,OAAOpB,aAC3BV,EAAYa,aAAaC,QAAQ,oBAAoB,EAErD+Y,EAAehZ,aAAaC,QAAQ,qBAAqB,EAE/DnC,IAAImb,EAQGA,EANa,IAAjBD,GAAuBA,EAMNA,GALF7a,MAAMmE,gBAAgBzC,EAAcV,EAAWiM,KAAKnK,OAAO3D,UAAW8N,KAAKnK,OAAOlB,SAAS,GAC7E4F,OAAOlD,GACxBA,EAAKlC,QACf,EAC0BwD,OAGzBmV,EAAmBlR,SAASM,eAAe,gCAAgC,EAC5E4Q,IACDA,EAAiBhR,UAAYC,WAAW8Q,CAAU,EAClDC,EAAiB9Q,UAAUC,OAAO,QAAQ,EAElD,CAYA4G,iBAAiBtP,GACRK,aAAaC,QAAQ,oBAAoB,IAC1C9B,MAAMyJ,aAAajI,CAAW,EAAEyL,KAAKiC,uBAAuB,EACvD1N,EAAYiJ,cACbzK,MAAMwK,UAAUhJ,CAAW,EAAEyL,KAAKiC,uBAAuB,GAIjE,IAAMlO,EAAYa,aAAaC,QAAQ,oBAAoB,EAE3D,OAAOd,EAIMyF,iBAAiBzF,EAAWQ,CAAW,EAFzC,CAACwP,YAAa,CAAA,CAAI,CAGjC,CAKA9E,OACI2G,wBAAwB,EACxB5F,KAAKwC,oBAAoB,MAAM,CAEnC,CAEAuL,gCAAgCjS,GAC5B,IAAMkS,EAAalS,EAAQmS,UAAU,EAC/BC,EAAUtR,SAASwH,cAAc,MAAM,EAM7C,OALA8J,EAAQ7J,UAAY,qDAEpBvI,EAAQqS,sBAAsB,cAAeD,CAAO,EACpDA,EAAQvI,YAAYqI,CAAU,EAEvBE,CACX,CAOApB,qBAAqBsB,GACjB,IAAM9E,EAAkBtJ,KAAKJ,aAAajG,KAAK,GAAamC,EAAQzG,OAAOmG,SAAS,IAAM4S,EAAe5S,SAAS,CAAC,EACnH,GAAI8N,GAAgDnX,KAAAA,IAA7BmX,EAAgBnU,SAAwB,CAC3DzC,IAAI2b,EAAsB,KAC1B,IACIA,EAAsBpV,KAAKC,MAAMoQ,EAAgBnU,QAAQ,CAG7D,CAFE,MAAOtC,GACLwb,EAAsB,IAC1B,CACA,GAA4B,OAAxBA,GAA+D,UAA/B,OAAOA,EACvC,OAAOA,CAEf,CACA,OAAO,IACX,CAEA5L,8BAEmB7F,SAAS6P,iBAAiB,4BAA4B,EAC9DC,QAAQhB,IACPA,EAAMvI,OACNuI,EAAM1O,UAAU8I,IAAI,WAAW,EAGnC4F,EAAM5M,iBAAiB,QAAS,KACxB4M,EAAMvI,MACNuI,EAAM1O,UAAU8I,IAAI,WAAW,EAE/B4F,EAAM1O,UAAUC,OAAO,WAAW,CAE1C,CAAC,EAEDyO,EAAM5M,iBAAiB,OAAQ,KACtB4M,EAAMvI,OACPuI,EAAM1O,UAAUC,OAAO,WAAW,CAE1C,CAAC,CACL,CAAC,EAnBD,IAsBMqR,EAAsB1R,SAASC,cAAc,iCAAiC,EACpF,GAAKyR,EAAsB,CACvB,IAAMC,EAAUvO,KAChBsO,EAAoBxP,iBAAiB,QAAS,WAC1CkB,KAAKT,QAAQ,4BAA4B,EAAEvC,UAAU4B,OAAO,QAAQ,EAEpE2P,EAAQlI,wBAAwB,EAChCrH,WAAW,KACP,IAAMkM,EAAmBtO,SAASC,cAAc,8BAA8B,EAC9EqO,EAAiBC,SAAS,CACtBC,IAAKF,EAAiBG,aACtBC,SAAU,QACd,CAAC,CACL,EAAG,CAAC,CACR,CAAC,CACL,CAEAtR,OAAO8E,iBAAiB,SAAUkB,KAAKwO,aAAaC,KAAKzO,IAAI,CAAC,EAC9DhG,OAAO8E,iBAAiB,SAAUkB,KAAK0O,aAAaD,KAAKzO,IAAI,CAAC,CAClE,CAEAiC,wBAAwB0M,EAAa5O,EAAO,SACxC,IAAM6O,EAAYhS,SAASM,eAAe,0CAA0C,EAC9E2R,EAAajS,SAASM,eAAe,mCAAmC,EACxE4R,EAAclS,SAASC,cAAc,sCAAsC,EAEtD,UAAvB,OAAO8R,GAA2C,OAAfE,GAAuC,OAAhBC,IAC1DD,EAAW/R,UAAYC,WAAW4R,CAAW,EAC7CG,EAAY9R,UAAUC,OAAO,QAAQ,EACrC4R,EAAW7R,UAAUC,OAAO,qCAAsC,mCAAmC,EACxF,WAAT8C,GACA6O,EAAU9R,UAAYC,WAAW,EAAE,EACnC+R,EAAY9R,UAAU8I,IAAI,oCAAoC,EAC9D+I,EAAWxP,MAAM0P,MAAQ,YAEzBH,EAAU9R,UAAYC,WAAW,oBAAoB,EACrD+R,EAAY9R,UAAU8I,IAAI,mCAAmC,EAC7D+I,EAAWxP,MAAM0P,MAAQ,OAGrC,CAEA1I,0BACI,IAAMN,EAAYnJ,SAASC,cAAc,qCAAqC,EACxEmS,EAASpS,SAASC,cAAc,sBAAsB,EACtDoS,EAAoBrS,SAASC,cAAc,+DAA+D,EAC1GqS,EAAsBtS,SAASC,cAAc,gDAAgD,EACnG,IAAWoS,GAAqBC,IAAyBnJ,EAAzD,CAKA,IAAMoJ,EAAUnV,OAAOmV,QACjBC,EAAiBpV,OAAOqV,YAExBC,EAAuBvJ,EAAUwJ,sBAAsB,EAAEnE,IAAM+D,EAE/DK,EAAeR,EAAOS,aAE5B/c,IAAI0Y,EAGAkE,EAAuBH,EAAU,EAEjC/D,EAAM,IACkCgE,EAAjCE,EAAuBH,GAMQC,EAAiBI,GADvDpE,EAAMkE,EAAuBH,MAGzB/D,EAAMgE,EAAiBI,EAAe,IAI9CR,EAAO3P,MAAM+L,IAASA,EAAH,KACnB4D,EAAO3P,MAAMqQ,OAAS,MA5BtB,CA6BJ,CAEAlB,eACItP,aAAac,KAAK2P,aAAa,EAC/B3P,KAAK2P,cAAgB3Q,WAAW,KAC5BgB,KAAKqG,wBAAwB,CACjC,EAAG,EAAE,CACT,CAEAqI,eACIxP,aAAac,KAAK4P,aAAa,EAC/B5P,KAAK4P,cAAgB5Q,WAAW,KAC5BgB,KAAKqG,wBAAwB,CACjC,EAAG,GAAG,CACV,CAOAyC,0BAA0BzB,GACtB,MAAO,CAAA,CACX,CAEAgB,iBAAiBjC,GACbyJ,EAAMxK,MAAMC,QAAQc,CAAQ,EAAInN,KAAKK,UAAU8M,CAAQ,EAAImD,OAAOnD,CAAQ,EAE9E,MAAI,kBAAkBsH,KAAKmC,CAAG,EACnBA,EAEJ,EACX,CACA,CAEA,IAAIC,wBAA0B,KAC9B,IAAMC,cAAgB,CAAA,EAChBC,mBAAqB,IAQ3B,SAASC,cACL,IAAIC,qBACJ,IAAI1Q,uBAAuB,GAAI,MAAM,CACzC,CA8CA,SAASgN,oBACL,IAAIhN,uBAAuB,KAAM,cAAc,CACnD,CAOA,SAAS2Q,sBAAsBC,GAC3B,GAAKA,EAAL,CACA1d,IAAI0M,EAAKgR,EAAKC,WAAaC,KAAKC,aAAeH,EAAOA,EAAKI,cAC3D,KAAOpR,GAAI,CACP,GAAIA,EAAGpC,WAAaoC,EAAGpC,UAAUsG,SAAS,qBAAqB,EAC3D,MAAO,CAAA,EAEXlE,EAAKA,EAAGoR,aACZ,CAPuB,CAQvB,MAAO,CAAA,CACX,CAOA,SAAS/J,kBAAkBpN,EAAc0G,GACjC1G,GACA,IAAImG,uBAAuBnG,EAAc0G,CAAI,CAErD,CAOA,SAAS0Q,gBAAgBtd,GAChB4c,eACD7D,QAAQC,IAAIhZ,CAAO,CAE3B,CAEA,SAAS8Q,wBACL,IAAMyM,EAAW9T,SAAS+T,uBAAuB,oDAAoD,EACrG,GAAsB,EAAlBD,EAAS/X,OACT,IAAKjG,IAAIwU,EAAI,EAAGA,EAAIwJ,EAAS/X,OAASuO,CAAC,GACnCwJ,EAASxJ,GAAG7H,MAAMC,QAAU,OAGpC,IAAMsR,EAAyB,CAAC,2CAA4C,iDAC5E,IAAKle,IAAIwU,EAAI,EAAGA,EAAI0J,EAAuBjY,OAASuO,CAAC,GAAI,CACrD,IAAM2J,EAAajU,SAAS+T,uBAAuBC,EAAuB1J,EAAE,EAC5E,GAAwB,EAApB2J,EAAWlY,OACX,IAAKjG,IAAIwU,EAAI,EAAGA,EAAI2J,EAAWlY,OAASuO,CAAC,GACrC2J,EAAW3J,GAAG7H,MAAMC,QAAU,OAG1C,CACJ,CAEA,SAASwI,mBAAmBgJ,EAAczb,GACtC,IAAM0C,EAAW+Y,EAAa/Y,SAASwC,OAAOvF,GACnCA,GAASK,QAAQmG,SAAS,IAAMnG,GAAQmG,SAAS,CAC3D,EACD,IAAMnD,EAAQyY,EAAazY,MAEvB0Y,EAAgC,EAAlBhZ,EAASY,OAAaZ,EAAS,GAAK,KAElDoE,EAAS,KAKExB,GAJXoW,GAAe1Y,GAAwB,EAAfA,EAAMM,SAC9BwD,EAAS9D,EAAMsB,KAAKoE,GAAKwL,OAAOxL,EAAE7J,OAAO,IAAMqV,OAAOwH,EAAY9c,MAAM,CAAC,GAGvD,IAClB8c,KACMC,EAAKxW,WAAWuW,EAAY9Y,WAAW,GACnCyC,KACVC,EAAOqW,EAAGrW,MAGdjI,IAAIue,EAAY/U,aAAaC,CAAM,EAC/B+U,EAAa5U,cAAcH,CAAM,EAErC,MAAO,CACH9G,OAAQA,EACRuG,uBAAwBqV,EACxBpV,eAAgBqV,EAChBjJ,gBAAiB8I,EAAcA,EAAY/Y,YAAc,kBACzDoQ,gBAAiBzN,EACjBzC,WAA8B,EAAlBH,EAASY,OAAaZ,EAAS,GAAGG,WAAa,WAC3DsN,cAAezN,EACV+O,KAAK,CAACC,EAAGC,IACC,IAAIlM,KAAKiM,EAAE9O,WAAW,EAAI,IAAI6C,KAAKkM,EAAE/O,WAAW,CAC1D,EACAb,IAAIpC,IACD,GAAM,CAAC0F,KAAAA,EAAMC,KAAAA,CAAI,EAAIH,WAAWxF,EAAQiD,WAAW,EACnDvF,IAAIyJ,EAAS,KAIb,MAAO,CACH+N,uBAAwBhO,aAHxBC,EADA9D,GAAwB,EAAfA,EAAMM,OACNN,EAAMsB,KAAKoE,GAAKwL,OAAOxL,EAAE7J,OAAO,IAAMqV,OAAOvU,EAAQf,MAAM,CAAC,EAGhCkI,CAAM,EAC3CgO,kBAAmB7N,cAAcH,CAAM,EACvCnE,YAAahD,EAAQgD,YACrBC,YAAayC,EACb2P,YAAa1P,EACbsP,cAAejV,EAAQf,QAAU,cACrC,CACJ,CAAC,CACT,CACJ,CAEA,SAAS4T,cAAcsJ,GACnBze,IAAI6V,EACAD,EACJ5V,IAAI8V,EACA2I,EAActV,gBAAkD,aAAhCsV,EAActV,eACxCsV,EAActV,eAAeU,KAAK,EAAE6U,OAAO,CAAC,EAAEC,YAAY,EAC1D,KACV3e,IAAI+V,EAAgB,sCAepB,OAd6C,OAAzC0I,EAAcvV,wBAA0D,OAAvB4M,IACjDD,EAAc,uFACdD,EAAiB,wCAEwB,OAAzC6I,EAAcvV,wBAA0D,OAAvB4M,IACjDD,EAAc,0jPACdD,EAAiB,uCACjBG,GAAiB,uCAEwB,OAAzC0I,EAAcvV,yBACd2M,2BAAwC4I,EAAcvV,4BACtD0M,EAAiB,uCACjBG,EAAgB,sCAEb,CACHF,YAAaA,EACbD,eAAgBA,EAChBE,mBAAoBA,EACpBC,cAAeA,CACnB,CACJ,CAOA,SAAS6I,iBAAiB1R,GACtBlN,IAEM6e,EAAkB,GAExB,IAAK7e,IAAIwU,EAAI,EAAGA,EAAItH,EAAajH,OAAQuO,CAAC,GAAI,CAC1C,IAAMsK,EAAqB5R,EAAasH,GAClCuK,EAAW7c,aAAaC,QAAQ,iBAAiB,EAEnD2c,EAAmBnc,QACnBmc,EAAmBla,gBACnBka,EAAmB9Z,oBAAoB8D,SAAS,IAAMiW,EAASjW,SAAS,GAE/DkW,uBAAuBF,EAAmBnc,OAAQmc,EAAmBla,cAAc,GAExFia,EAAgB/S,KAAKgT,EAAmBnc,OAAOmG,SAAS,CAAC,CAGrE,CAEA,OAAkC,IAA3B+V,EAAgB5Y,QAAuB4Y,CAClD,CAMAxf,eAAesQ,gCAAgCzC,EAAc/J,GACzD,IAAM8b,EAAiBL,iBAAiB1R,CAAY,EACpDlN,IAAIoB,EAAS,CAAA,EACb,GAAI,CAAC6d,EACD,MAAO,CAAA,EAEX,IAAKjf,IAAIwU,EAAI,EAAGA,EAAIyK,EAAehZ,OAAQuO,CAAC,GAAI,CAC5C,IAIc0K,EAJRC,EAAgBF,EAAezK,GACR,UAAzB,OAAO2K,IACDC,EAAmB/e,MAAM0G,oBAAoB5D,EAAQ,CAACgc,EAAc,GACtD9Z,UAGkB5F,KAAAA,KAF5Byf,EAAcE,EAAgB/Z,SAAS,IAE7BkS,eACZ2H,EAAY3H,gBAAkBrV,aAAaC,QAAQ,iBAAiB,GAClC,cAAlC+c,EAAYzH,oBAEZ4H,gCAAgCF,CAAa,EAC7C/d,EAAS,CAAA,EAIzB,CACA,OAAOA,CACX,CAOA,SAASke,mBAAmBjM,GACxB,MAAO,CAAA,CACX,CAQA,SAAShJ,WAAWkV,EAAMC,EAAU,CAAA,GAChCxf,IAAIyf,EAAc,CACdpL,EAAG,CAAA,EACHC,EAAG,CAAA,EACHE,EAAG,CAAA,EACHkL,OAAQ,CAAA,EACRC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,GAAI,CAAA,EACJC,EAAG,CAAA,EACHrJ,EAAG,CAAA,EACHsJ,GAAI,CAAA,EACJC,KAAM,CAAA,EACNC,WAAY,CAAA,EAQZA,WAAY,CAAA,EAPZC,IAAK,CAAA,EAQLA,IAAK,CAAA,EAPLC,IAAK,CAAA,EACLC,IAAK,CAAA,EACLrH,MAAO,CAAA,EACPsH,MAAO,CAAA,EACPhI,SAAU,CAAA,EACViI,OAAQ,CAAA,EAGRC,QAAS,CAAA,EACTC,QAAS,CAAA,CACb,EACIC,EAAe,CACfrM,EAAG,CAAC,OAAQ,QAAS,SAAU,MAAO,QAAS,SAC/C4L,KAAM,CAAC,QAAS,QAAS,MACzBF,EAAG,CAAC,QAAS,SACbK,IAAK,CAAC,QAAS,QAAS,KAAM,iBAAkB,gBAChDC,IAAK,CAAC,MAAO,MAAO,QAAS,QAAS,QAAS,QAAS,UACxDrH,MAAO,CAAC,OAAQ,QAAS,QAAS,KAAM,WAAY,SAAU,SAC9DsH,MAAO,CAAC,MAAO,QAAS,SACxBhI,SAAU,CAAC,QAAS,KAAM,QAAS,OAAQ,OAAQ,WAAY,WAAY,QAC3EiI,OAAQ,CAAC,OAAQ,QAAS,QAAS,MACnCC,QAAS,CAAC,QAAS,QAAS,QAC5BC,QAAS,CAAC,QAAS,QACvB,EAEIjB,GAAgC,gBAArBA,EAAQlF,WACnBmF,EAAc,CAAE,GAAGA,EAAaO,GAAI,CAAA,CAAM,GAI9C,IAAMW,GADS,IAAIC,WACAC,gBAAgBtB,EAAM,WAAW,EAwDpD,MADA,CAAC,GAAGoB,EAAIpgB,KAAKugB,YAAY9G,QAtDzB,SAAS+G,EAAMrD,GACX,GAAIA,EAAKC,WAAaC,KAAKC,aAAc,CACrC,IAAMmD,EAAMtD,EAAKuD,QAAQC,YAAY,EAErC,GAAI1B,EAAS,CAGL,IAGU2B,EAkBAlR,EACAmR,EACAD,EAzBd,GAAI1B,EAAYuB,IAEA,QAARA,GAAsC,+BAArBxB,EAAQlF,UAA6CkF,EAAQ5E,UAc9E,OAbM3K,EAAMyN,EAAKzD,aAAa,KAAK,GAAK,GAClCmH,EAAM1D,EAAKzD,aAAa,KAAK,GAAK,WAClCkH,EAAOR,EAAIjP,cAAc,GAAG,GAC7BlK,KAAOyI,EACZkR,EAAKE,OAAS,SACdF,EAAKxP,UAAY,gCACX0O,EAAMM,EAAIjP,cAAc,KAAK,GAC/BzB,IAAMA,EACVoQ,EAAIe,IAAMA,EACVf,EAAI1O,UAAY,8CAChBwP,EAAKlO,YAAYoN,CAAG,EACpB3C,EAAK4D,WAAWC,aAAaJ,EAAMzD,CAAI,EAJvC2C,KAKA3C,EAAKnT,OAAO,EAKpB,GAAI,CAACkV,EAAYuB,GAYb,MAVY,QAARA,GAAsC,gBAArBxB,EAAQlF,UAA8BkF,EAAQ5E,YACzD3K,EAAMyN,EAAKzD,aAAa,KAAK,GAAK,GAClCmH,EAAM1D,EAAKzD,aAAa,KAAK,GAAK,WAClCkH,EAAOR,EAAIjP,cAAc,GAAG,GAC7BlK,KAAOyI,EACZkR,EAAKE,OAAS,SACdF,EAAKK,YAAcJ,EACnB1D,EAAK4D,WAAWC,aAAaJ,EAAMzD,CAAI,GAP3C,KASAA,EAAKnT,OAAO,CAGpB,CAGA,CAAC,GAAGmT,EAAK+D,YAAYzH,QAAQ0H,IACzB,IAAMC,EAAWD,EAAKtf,KAAK8e,YAAY,EAClCR,EAAaM,IAAM7Y,SAASwZ,CAAQ,GACrCA,CAAAA,EAASC,WAAW,IAAI,GACxBF,CAAAA,EAAKjR,MAAMyQ,YAAY,EAAE/Y,SAAS,aAAa,GAC/CuV,EAAK7L,gBAAgB6P,EAAKtf,IAAI,CAEtC,CAAC,CACL,CAEA,CAAC,GAAGsb,EAAKoD,YAAY9G,QAAQ+G,CAAK,CACtC,CACsC,EAC/BJ,EAAIpgB,KAAKqR,SACpB,CAtX4B,YAAxB1H,SAAS2X,WACT3X,SAASkC,iBAAiB,gBAAiBmR,WAAW,EAEtDrT,SAASkC,iBAAiB,mBAAoBmR,WAAW,EAQ7DrT,SAASkC,iBAAiB,kBAAmB,SAASyG,GAGlD,IAKMiP,EALFjP,EAAEwO,SAAWnX,WAIX6X,EAA2B,CAAC,CAAE7X,SAAS+T,uBAAuB,aAAa,EAAE,IAC7E6D,EAAM5X,SAASoJ,aAAa,IAEF,KAAnBwO,EAAIhZ,SAAS,GAAaiZ,CAAAA,GAKnC3E,yBACA5Q,aAAa4Q,uBAAuB,EAGxCA,wBAA0B9Q,WAAW,KACjC,IAMQ0V,EAIErb,EAVJ0M,EAAY/L,OAAOgM,aAAa,EAEf,UAAnBD,EAAUhG,OAGN4U,EAAa5O,EAAU4O,WACvBD,EAAY3O,EAAU2O,UACtBvE,sBAAsBwE,CAAU,GAAKxE,sBAAsBuE,CAAS,IAGlErb,EAAe8M,uBAAuBJ,CAAS,IAIjDU,kBAAkBpN,EAAc,aAAa,EAGzD,EAAG2W,kBAAkB,GA1BjB,IAAIxQ,uBAAuB,GAAI,MAAM,EA2B7C,CAAC,EA8UD,IAAMoV,4BAA8B,OAC9BC,2BAA6B,QAC7BC,+BAAiC,UAOvC,SAASC,wBAAwBhP,GAC7B,IAAMiP,EAAQjP,EAAUkP,WAAW,CAAC,EAC9BC,EAAiBF,EAAMG,wBAG7B,OAAIC,wBAAwBrP,CAAS,EAC1B8O,2BAIPK,EAAe7E,WAAaC,KAAKC,cACE,EAAnC2E,EAAe1B,WAAW7a,QACE,KAA5Bqc,EAAMxZ,SAAS,EAAEe,KAAK,GACtByY,EAAMK,iBAAmBL,EAAMM,cAC/BN,EAAMK,eAAehF,WAAaC,KAAKC,aAChCuE,gCAILS,EAAkD,EAAjCP,EAAMxZ,SAAS,EAAEe,KAAK,EAAE5D,OACzC6c,EAAaN,EAAe7E,WAAaC,KAAKmF,UAC9CC,EAAcV,EAAMW,UAEtBJ,CAAAA,GAAmBC,CAAAA,GAAeE,EAI/B,KAHId,4BAIf,CAOA,SAASzO,uBAAuBJ,GAG5B,GAAI,CAACA,EAA0F,OAA9E0K,gBAAgB,2DAA2D,EAAU,KAEtG,GAA6B,IAAzB1K,EAAU6P,WAA8F,OAA1EnF,gBAAgB,uDAAuD,EAAU,KAEnH,GAA2B,EAAvB1K,EAAU6P,WAAiG,OAA/EnF,gBAAgB,4DAA4D,EAAU,KAEtH,IAAMuE,EAAQjP,EAAUkP,WAAW,CAAC,EAEpC,GAAID,EAAMK,iBAAmBL,EAAMM,aAA2G,OAA3F7E,gBAAgB,wEAAwE,EAAU,KAGrJ,IAAMoF,EAAgBd,wBAAwBhP,CAAS,EAGvD,GAAI,CAAC8P,EAAsG,OAArFpF,gBAAgB,kEAAkE,EAAU,KAGlH/d,IAAIyG,EAAe,GACf2c,EAAsB,EACtBC,EAAoB,EACpB3P,EAAW,GACf1T,IAEMsjB,EAAahB,EAAMG,wBAEzB,OAAQU,GACJ,KAAKjB,4BACD,GAAuC,IAAnCI,EAAMxZ,SAAS,EAAEe,KAAK,EAAE5D,OAExB,OADA8X,gBAAgB,4DAA4D,EACrE,KAEX,IAAMwF,EAAoBD,EAAW3F,WAAaC,KAAKC,aAAeyF,EAAaA,EAAWxF,cAC9FrX,EAAe6b,EAAMxZ,SAAS,EAC9Bsa,EAAsBd,EAAMkB,YAC5BH,EAAoBf,EAAMmB,UACG,IAAxBL,GAA6B3c,EAAaR,OAASod,IACpDA,EAAoB5c,EAAaR,QAErCyN,EAAWgQ,yBAAyBH,CAAiB,EACrD,MAEJ,KAAKpB,2BACD,IAAMwB,EAAarB,EAAMK,eACnBiB,EAAgBlB,wBAAwBrP,CAAS,EACvD5M,YAAyBmd,EAAcxC,KAA0B,oBACjE1N,EAAWgQ,yBAAyBE,CAAa,EAEjDR,EAAsBzQ,MAAMkR,KAAKF,EAAWrC,WAAWwC,QAAQ,EAAEC,QAAQJ,CAAU,EACnFN,EAAoBD,EAAsB,EAC1C,MAEJ,KAAKhB,+BACKhZ,EAAUka,EAAW3F,WAAaC,KAAKC,aAAeyF,EAAaA,EAAWxF,cACpF,GAAI1U,EAAQ0X,WAAW7a,QAAU,EAE7B,OADA8X,gBAAgB,kEAAkE,EAC3E,KAEXtX,EAAe2C,EAAQoY,aAAe,GACtC9N,EAAWgQ,yBAAyBta,CAAO,EAE3Cga,EAAsBzQ,MAAMkR,KAAKza,EAAQkY,WAAWwC,QAAQ,EAAEC,QAAQ3a,CAAO,EAC7Eia,EAAoBD,EAAsB,CAElD,CAGA,IAAMvf,EAAUyD,OAAOC,SAASC,KAEhC,MAAO,CACH4b,oBAAAA,EACAC,kBAAAA,EACA5c,aAAcA,EAAaoD,KAAK,EAChChG,QAAAA,EACA6P,SAAAA,EACAyP,cAAAA,EACAa,UAA4B7B,2BAtDjB,GAuDf,CACJ,CAOA,SAAS9L,yBAAyBpC,EAAsBgQ,GAEpD,GAAoC,IAAhChQ,EAAqBhO,OAAzB,CAEA,IAAMie,EAAc,IAAIC,IAGxBlQ,EAAqB+F,QAAQoK,IAEzB,IAWMhb,EAXDgb,GAAM1Q,UAAaf,MAAMC,QAAQwR,GAAM1Q,QAAQ,EAM/CpG,KAAK+W,uBAAuBD,EAAK1Q,QAAQ,GAKxCtK,EAAUkb,4BAA4BF,EAAK1Q,QAAQ,GAMlD0Q,EAAKjB,cASRiB,EAAKjB,eACL,CAAC,CACGjB,4BACAC,2BACAC,gCACFja,SAASic,EAAKjB,aAAa,EAE7BpF,gBAAgB,2BAA6BqG,EAAKjB,aAAa,GAI9De,EAAYK,IAAInb,CAAO,GACxB8a,EAAYM,IAAIpb,EAAS,EAAE,EAE/B8a,EAAYlV,IAAI5F,CAAO,EAAE0C,KAAKsY,CAAI,GApB9BrG,gBAAgB,iCAAiC,EAPjDA,gBAAgB,+BAAiCqG,EAAK1Q,QAAQ,EAN9DqK,gBAAgB,4BAA8BqG,EAAK1Q,QAAQ,EAN3DqK,gBAAgB,8CAAgDqG,CAAI,CAwC5E,CAAC,EAEDF,EAAYlK,QAAQ,CAACyK,EAAOrb,KACxB,IAAM+Z,EAAgBsB,EAAM,GAAGtB,cAG/B,OAAQA,GACJ,IAAK,QACD7V,KAAKoX,6BAA6Btb,CAAO,EACzC,MAEJ,IAAK,UACDkE,KAAKqX,8BAA8Bvb,CAAO,EAC1C,MAEJ,IAAK,OACDkE,KAAKsX,8BAA8Bxb,EAASqb,EAAOR,CAAc,EACjE,MAEJ,QACIlG,gBAAgB,2BAA6BoF,CAAa,CAClE,CACJ,CAAC,CAtE4C,CAuEjD,CAMA,SAASuB,6BAA6Btb,GACV,QAApBA,EAAQ6X,QACRlD,gBAAgB,kDAAoD3U,EAAQ6X,OAAO,EAGvF7X,EAAQkB,UAAU8I,IAAI,qCAAqC,CAC/D,CAMA,SAASuR,8BAA8Bvb,GACnCA,EAAQkB,UAAU8I,IAAI,uCAAuC,CACjE,CAQA,SAASwR,8BAA8Bxb,EAASqb,EAAMR,GAClDjkB,IAAI6kB,EAAmB,GAevB,IAAMC;;;uCAbFD,EADAJ,EAAM,GAAG7P,QACU,4BAEA;2IAOgH6P,EAAM,GAAG9hB;;yCAO5IoiB,EAAO3b,EAAQoY,YACnB,IAAMwD,EAAmBP,EAAM,GAAGhe,aAGlC,GAAOue,EAAP,CAKA,IAAMC,EAAU,GAiBhB,GAdAR,EAAMzK,QAAQoK,IAEV,IAAMc,EAAWC,SAASf,EAAKhB,mBAAmB,GAAK,EACjDgC,EAASD,SAASf,EAAKf,iBAAiB,GAAK,EAE/C6B,EAAW,GAAKE,EAASL,EAAK9e,QAAqBmf,EAAXF,EACxCnH,gBAAgB,2BAA6BqG,CAAI,GAIrDa,EAAQnZ,KAAK,CAAEuZ,SAAUH,EAAU7X,KAAM,OAAQ,CAAC,EAClD4X,EAAQnZ,KAAK,CAAEuZ,SAAUD,EAAQ/X,KAAM,KAAM,CAAC,EAClD,CAAC,EAEsB,IAAnB4X,EAAQhf,OAOZ,GAJAgf,EAAQ7Q,KAAK,CAACC,EAAGC,IAAMA,EAAE+Q,SAAWhR,EAAEgR,QAAQ,EAIzCN,EAAKO,MAAML,EAAQ,GAAGI,SAAUJ,EAAQ,GAAGI,QAAQ,IAAML,EAC1DjH,gBAAgB,4DAA4D,MADhF,CAKA/d,IAAIoB,EAAS2jB,EACbE,EAAQjL,QAAQuL,IACZ,IAAMC,EAA6B,UAAhBD,EAAOlY,KACpByX,EA3CoB,UA8C1B1jB,EAASA,EAAOkkB,MAAM,EAAGC,EAAOF,QAAQ,EAAIG,EAAapkB,EAAOkkB,MAAMC,EAAOF,QAAQ,CACzF,CAAC,EAGD,IACIjc,EAAQwI,UAAYvH,WAAWjJ,CAAM,EACrC8I,SAAS6P,iBAAiB,+BAA+B,EAAEC,QAAQmH,IAC/DA,EAAK/U,iBAAiB,QAAS,IAE3ByG,EAAEkG,eAAe,EAEX0M,EADYtE,EAAKxP,UAAUhG,MAAM,GAAG,EAChB1E,KAAKye,GAAOA,EAAIvd,SAAS,YAAY,CAAC,EAChEnI,IAAI2C,EAAS,MAETA,EADA8iB,EACSA,EAAQ9Z,MAAM,YAAY,EAAE,GAErChJ,KACAshB,EAAejd,oBAAsBrE,EACrCshB,EAAe/J,YAAY,EAEnC,CAAC,CACL,CAAC,CAGL,CAFE,MAAO/Z,GACL4d,gBAAgB,mCAAqC5d,CAAK,CAC9D,CAhCA,CA7BA,MAFI4d,gBAAgB,+BAA+B,CAgEvD,CAOA,SAASvK,wBAAwBmS,GACvBjI,EAAO4G,4BAA4BqB,CAAI,EAC7C,MAAA,EAAIjI,CAAAA,GAAQA,CAAAA,EAAKkI,iBACblI,EAAKkI,eAAe,CAAEhN,SAAU,SAAUiN,MAAO,QAAS,CAAC,EACpD,GAGf,CAEA,SAAS3S,0BACL,IACM4S,EAAQ5b,SAAS6P,iBAAiB,qCAA4B,EACpE,IAAMgM,EAAkB,IAAIC,IAkBtBC,GAhBNH,EAAM9L,QAAQiG,IACV,IAAMiG,EAASjG,EAAKqB,WAEd6E,GADNJ,EAAgB3S,IAAI8S,CAAM,EACVjG,EAAK9V,cAAc,6CAA6C,GAIhF,IAHIgc,GAASA,EAAQ5b,OAAO,EAGrB0V,EAAKmG,YACRF,EAAO3E,aAAatB,EAAKmG,WAAYnG,CAAI,EAE7CiG,EAAOG,YAAYpG,CAAI,CAC3B,CAAC,EAGD8F,EAAgB/L,QAAQkM,GAAUA,EAAOI,UAAU,CAAC,EAElB,yCAK5BC,GAJWrc,SAAS6P,iBAAiB,IAAIkM,CAA2B,EACjEjM,QAAQ5Q,IACbA,EAAQkB,UAAUC,OAAO0b,CAAyB,CACtD,CAAC,EAC+B,uCACjB/b,SAAS6P,iBAAiB,IAAIwM,CAAyB,EAC/DvM,QAAQ5Q,IACXA,EAAQkB,UAAUC,OAAOgc,CAAuB,CACpD,CAAC,CACL,CAOA,SAASlC,uBAAuB3Q,GAC5B,MAAKf,CAAAA,CAAAA,MAAMC,QAAQc,CAAQ,GACH,IAApBA,EAASzN,QAENyN,EAAS8S,MAAMC,GACXnP,OAAOoP,UAAUD,CAAK,GAAc,GAATA,GAAcA,EAAQ,GAC3D,CACL,CAOA,SAAS/D,wBAAwBrP,GAE7B,GAAKA,GAAsC,IAAzBA,EAAU6P,YAAoB7P,CAAAA,EAAU2P,YAA1D,CAIA,IAAMV,EAAQjP,EAAUkP,WAAW,CAAC,EAGpC,GAAID,EAAMK,iBAAmBL,EAAMM,cAC/BN,EAAMK,eAAehF,WAAaC,KAAKC,cACN,QAAjCyE,EAAMK,eAAe1B,QACrB,OAAOqB,EAAMK,eAiBbgE,EAbWzc,SAAS0c,iBACpBtE,EAAMG,wBACNoE,WAAWC,aACX,CACIC,WAAY,SAASrJ,GACjB,MAAwB,QAAjBA,EAAKuD,SACZ+F,wBAAwBtJ,EAAM4E,CAAK,EAC/BuE,WAAWI,cACXJ,WAAWK,aACnB,CACJ,CACJ,EAEqBC,SAAS,EAC9B,GAAIR,EACA,OAAOA,EAIX,IAgBWvd,EAhBLge,EAAeC,0BAA0B/E,EAAMK,cAAc,EAC7D2E,EAAaD,0BAA0B/E,EAAMM,YAAY,EAG/D,GAAIwE,GAAyC,QAAzBA,EAAanG,SAC7BsG,kCAAkCH,EAAc9E,CAAK,EACrD,OAAO8E,EAGX,GAAIE,GAAqC,QAAvBA,EAAWrG,SACzBsG,kCAAkCD,EAAYhF,CAAK,EACnD,OAAOgF,EAKX,IAAWle,KADYoe,0BAA0BlF,CAAK,EAElD,GAAwB,QAApBlZ,EAAQ6X,QACR,OAAO7X,CAjDf,CAqDA,OAAO,IACX,CAEA,SAAS4d,wBAAwB5d,EAASkZ,GACtC,IAAMmF,EAAevd,SAASwd,YAAY,EAE1C,OADAD,EAAaE,WAAWve,CAAO,EACxBkZ,EAAMsF,sBAAsBC,MAAMC,eAAgBL,CAAY,GAAK,GACP,GAA/DnF,EAAMsF,sBAAsBC,MAAME,WAAYN,CAAY,CAClE,CAEA,SAASF,kCAAkCne,EAASkZ,GAC1C0F,EAAc5e,EAAQyT,sBAAsB,EAC5CoL,EAAY3F,EAAMzF,sBAAsB,EAG9C,MAAO,EAAEmL,EAAYE,MAAQD,EAAUE,MACnCH,EAAYG,KAAOF,EAAUC,OAC7BF,EAAYhL,OAASiL,EAAUvP,KAC/BsP,EAAYtP,IAAMuP,EAAUjL,OACpC,CAEA,SAASqK,0BAA0B3J,GAC/B,OAAOA,EAAKC,WAAaC,KAAKC,aAAeH,EAAOA,EAAKI,aAC7D,CAOA,SAAS0J,0BAA0BlF,GAC/B,IAAM8F,EAAW,GACXjV,EAAYmP,EAAMG,wBAGlB4F,EAAkBlV,EAAUmV,uBAC5BC,EAAcpV,EAAUqV,mBAU9B,GARIH,GACAD,EAAStc,KAAKuc,CAAe,EAE7BE,GACAH,EAAStc,KAAKyc,CAAW,EAIzBpV,EAAUwK,WAAaC,KAAKC,aAAc,CAC1C,IAAMiG,EAAW3Q,EAAU2Q,SAC3B,IAAK9jB,IAAIwU,EAAI,EAAGA,EAAIsP,EAAS7d,OAAQuO,CAAC,GAC9B+S,kCAAkCzD,EAAStP,GAAI8N,CAAK,GACpD8F,EAAStc,KAAKgY,EAAStP,EAAE,CAGrC,CAEA,OAAO4T,CACX,CAQA,SAAS1E,yBAAyBhG,GAE9B,IADA1d,IAAI2lB,EAAO,GACJjI,GAAM,CACT1d,IAAIymB,EAAQ,EACRgC,EAAU/K,EAAKgL,gBACnB,KAAOD,GACsB,IAArBA,EAAQ9K,UACR8I,CAAK,GAETgC,EAAUA,EAAQC,gBAEtB/C,EAAKgD,QAAQlC,CAAK,EAClB/I,EAAOA,EAAK4D,UAChB,CAKA,OAFAqE,EAAKiD,MAAM,EAEJjD,CACX,CAQA,SAASrB,4BAA4BqB,GAEjC,GAAK,CAAEA,EACH,OAAO,KAGX3lB,IAAI0d,EAAOxT,SACX,IAAKlK,IAAIwU,EAAI,EAAGA,EAAImR,EAAK1f,OAAQuO,CAAC,GAE9B,GAAK,EADLkJ,EAAOA,EAAKoG,SAAS6B,EAAKnR,KAEtB,OAAO,KAGf,OAAOkJ,CACX,CAEA1d,IAAI6oB,qywBAKJ,SAASxW,2BACL,MAA4D,MAArDnQ,aAAaC,QAAQ,0BAA0B,CAC1D,CAMA,SAAS0N,0BACL,OAA4D,OAArD3N,aAAaC,QAAQ,0BAA0B,CAC1D,CAMA,SAAS+M,yBAAyB4Z,GAC9B5mB,aAAaqC,QAAQ,2BAA4BukB,EAAU,IAAM,GAAG,CACxE,CAMA,SAAS1W,0BACL,OAAmD,OAA5ClQ,aAAaC,QAAQ,iBAAiB,CACjD,CAMA,SAASyN,2BAA2BnL,GAChC,GAAKA,GAAUkO,MAAMC,QAAQnO,CAAK,EAAlC,CAIAzE,IAAI+oB,EAAc,GAClB,IACIA,EAAcxiB,KAAKC,MAAMtE,aAAaC,QAAQ,sBAAsB,GAAK,IAAI,CAGjF,CAFE,MAAOhC,GACL4oB,EAAc,EAClB,CAEAtkB,EAAMuV,QAAQrV,IACNA,EAAKhC,QAAUgC,EAAKC,iBACpBmkB,EAAYpkB,EAAKhC,QAAU,CACvBA,OAAQgC,EAAKhC,OACbiC,eAAgBD,EAAKC,cACzB,EAER,CAAC,EAED1C,aAAaqC,QAAQ,uBAAwBgC,KAAKK,UAAUmiB,CAAW,CAAC,CAlBxE,CAmBJ,CAEA,SAAS5jB,sBAAsBV,GACtBA,GAAUkO,MAAMC,QAAQnO,CAAK,IAI5BukB,EAAQvkB,EAAMoD,OAAOlD,GAChBA,EAAKlC,QACf,GAAGwD,OAEJ/D,aAAaqC,QAAQ,sBAAuB,GAAGykB,CAAO,EAC1D,CAQA,SAAShK,uBAAuBrc,EAAQsmB,GACpC,GAAI,CAACtmB,GAAU,CAACsmB,EACZ,OAAO,KAGXjpB,IAAI+oB,EAAc,GAClB,IACIA,EAAcxiB,KAAKC,MAAMtE,aAAaC,QAAQ,sBAAsB,GAAK,IAAI,CAGjF,CAFE,MAAOhC,GACL4oB,EAAc,EAClB,CACMG,EAAaH,EAAYpmB,GAE/B,MAAKumB,CAAAA,CAAAA,GAIgB,IAAI9gB,KAAK8gB,EAAWtkB,cAAc,EACjC,IAAIwD,KAAK6gB,CAAiB,CAEpD,CAMA,SAAS5J,gCAAgC1c,GACrC,GAAKA,EAAL,CAIA3C,IAAImpB,EAAe,GACnB,IACIA,EAAe5iB,KAAKC,MAAMtE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACLgpB,EAAe,EACnB,CAEKA,EAAahhB,SAASxF,CAAM,GAC7BwmB,EAAard,KAAKnJ,CAAM,EAG5BT,aAAaqC,QAAQ,yBAA0BgC,KAAKK,UAAUuiB,CAAY,CAAC,CAb3E,CAcJ,CAMA,SAAS/R,mCAAmCzU,GACxC,GAAKA,EAAL,CAIA3C,IAAImpB,EAAe,GACnB,IACIA,EAAe5iB,KAAKC,MAAMtE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACLgpB,EAAe,EACnB,CACAA,EAAeA,EAAathB,OAAOuhB,GAAMA,IAAOzmB,CAAM,EACtDT,aAAaqC,QAAQ,yBAA0BgC,KAAKK,UAAUuiB,CAAY,CAAC,CAT3E,CAUJ,CAMA,SAASzZ,+BACL1P,IAAImpB,EAAe,GACnB,IACIA,EAAe5iB,KAAKC,MAAMtE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACLgpB,EAAe,EACnB,CAEA,OAA6B,EAAtBA,EAAaljB,MACxB,CAOA,SAASkQ,oCAAoCxT,GACzC,GAAI,CAACA,EACD,MAAO,CAAA,EAGX3C,IAAImpB,EAAe,GACnB,IACIA,EAAe5iB,KAAKC,MAAMtE,aAAaC,QAAQ,wBAAwB,GAAK,IAAI,CAGpF,CAFE,MAAOhC,GACLgpB,EAAe,EACnB,CAEA,OAAOA,EAAahhB,SAASxF,EAAOmG,SAAS,CAAC,CAClD,OAMM2F,aAKFrB,YAAYic,GAER/b,KAAKgc,MAAQ,GAGbhc,KAAKic,YAAc,QAGnBjc,KAAKkc,aAAe,SAGpBlc,KAAKmc,SAAW,EAGhBnc,KAAKoc,aAAe,CAAC,aAAc,YAAa,YAAa,kBAAmB,aAAc,sBAG9Fpc,KAAK+b,kBAAoBA,EAGzB/b,KAAKqc,WAAa,CAAC,QAAS,KAAM,KAAM,KAC5C,CAMApc,OACID,KAAKsc,mBAAmB,EACxBtc,KAAKuc,qBAAqB,CAC9B,CAMAD,qBAEItc,KAAKwc,UAAY5f,SAASM,eAAe,qDAAqD,EAG9F8C,KAAKyc,SAAW7f,SAASM,eAAe,6CAA6C,EAErF8C,KAAK0c,gBAAkB9f,SAASM,eAAe,2CAA2C,EAG1F8C,KAAKxM,aAAeoJ,SAASM,eAAe,yCAAyC,EAEhF8C,KAAKwc,WAAcxc,KAAKyc,UAAazc,KAAKxM,cAAgBwM,CAAAA,KAAK0c,iBAChExQ,QAAQyQ,KAAK,kCAAkC,CAEvD,CAMAJ,uBACQvc,KAAKwc,WACLxc,KAAKwc,UAAU1d,iBAAiB,SAAU,GAAOkB,KAAK4c,sBAAsBrX,CAAC,CAAC,CAEtF,CAOAgH,oBAAoBzQ,GAChBA,EAAQgD,iBAAiB,QAAS,IAC9ByG,EAAEkG,eAAe,EACbzL,KAAKwc,WACLxc,KAAKwc,UAAUK,MAAM,CAE7B,CAAC,CACL,CAOAD,sBAAsBE,GAClB9c,KAAK+c,WAAW,EAEhB,IAAMC,EAAgB3X,MAAMkR,KAAKuG,EAAM/I,OAAOiI,KAAK,EAC/Chc,KAAKgc,MAAMrjB,OAASqkB,EAAcrkB,OAASqH,KAAKmc,SAChDnc,KAAKgM,qBAAqBhM,KAAKmc,iCAAiC,GAGjDa,EAAcziB,OAAOtE,GAAQ+J,KAAKid,aAAahnB,CAAI,CAAC,EAE5DyW,QAAQzW,GAAQ+J,KAAKkd,QAAQjnB,CAAI,CAAC,EAG7C6mB,EAAM/I,OAAO5Q,MAAQ,GAGrBnD,KAAK0c,gBAAgBrd,MAAMC,QAAU,QACzC,CAOA2d,aAAahnB,GAET,OAAIA,EAAKknB,KAAOnd,KAAKic,aACjBjc,KAAKgM,mBAAmB/V,EAAKnB,qCAAqCkL,KAAKod,eAAepd,KAAKic,WAAW,CAAG,EAClG,CAAA,GAIOjc,KAAKqd,aAAa,EAAIpnB,EAAKknB,KAC7Bnd,KAAKkc,cACjBlc,KAAKgM,UAAU,uCAAuChM,KAAKod,eAAepd,KAAKkc,YAAY,CAAG,EACvF,CAAA,GAIX,EAA+B,EAA3Blc,KAAKoc,aAAazjB,QAAeqH,CAAAA,KAAKoc,aAAavhB,SAAS5E,EAAK8J,IAAI,IACrEC,KAAKgM,wBAAwB/V,EAAK8J,cAAc9J,EAAKnB,yBAAyB,EACvE,GAIf,CAMAuoB,eACI,OAAOrd,KAAKgc,MAAMsB,OAAO,CAACC,EAAK3nB,IAAa2nB,EAAM3nB,EAASK,KAAKknB,KAAM,CAAC,CAC3E,CAOAD,QAAQjnB,GACEunB,EAAa,CACf1B,GAAI9b,KAAKyd,eAAe,EACxBxnB,KAAMA,CACV,EAEA+J,KAAKgc,MAAMxd,KAAKgf,CAAU,EAC1Bxd,KAAK0d,eAAe,CACxB,CAOAD,iBACI,OAAO3iB,KAAK6iB,IAAI,EAAIC,KAAKC,OAAO,EAAEriB,SAAS,EAAE,EAAEsiB,OAAO,EAAG,CAAC,CAC9D,CAOAC,WAAWC,GACPhe,KAAKgc,MAAQhc,KAAKgc,MAAMzhB,OAAO0jB,GAAKA,EAAEnC,KAAOkC,CAAM,EACnDhe,KAAK0d,eAAe,EACpB1d,KAAK+c,WAAW,CACpB,CAMAW,iBACI,IAOMQ,EAPDle,KAAKyc,WAEgB,IAAtBzc,KAAKgc,MAAMrjB,OACXqH,KAAKyc,SAASnY,UAAYvH,WAAW,4EAA4E,GAI/GmhB,EAAYle,KAAKgc,MAAM5kB,IAAIxB,GAAYoK,KAAKme,eAAevoB,CAAQ,CAAC,EAC1EoK,KAAKyc,SAASnY,UAAYvH,WAAW,EAAE,EACvCmhB,EAAUxR,QAAQ9S,GAAQoG,KAAKyc,SAAS9W,YAAY/L,CAAI,CAAC,GAC7D,CASAukB,eAAevoB,GACX,GAAM,CAAEK,KAAAA,EAAM6lB,GAAAA,CAAG,EAAIlmB,EACfwoB,EAAWxhB,SAASwH,cAAc,KAAK,EAgB7C,OAfAga,EAAS/Z,UAAY,8CAErB+Z,EAAS9Z,UAAYvH;;;+EAGkDiD,KAAK+b,kBAAkBxS,OAAOtT,EAAKnB,IAAI,CAAC;+EACxCkL,KAAKod,eAAennB,EAAKknB,IAAI;;;uGAGLrB;SAC9F,EAEiBsC,EAASvhB,cAAc,+CAA+C,EAC9EiC,iBAAiB,QAAS,IAAMkB,KAAK+d,WAAWjC,CAAE,CAAC,EAEtDsC,CACX,CAOAhB,eAAeiB,GACX,IAGMnX,EAHN,OAAc,IAAVmX,EAAoB,WAGlBnX,EAAI0W,KAAKU,MAAMV,KAAKzR,IAAIkS,CAAK,EAAIT,KAAKzR,IADlC,IACuC,CAAC,EAE3CoS,YAAYF,EAAQT,KAAKY,IAHtB,KAG6BtX,CAAC,GAAGuX,QAAQ,CAAC,CAAC,EAAI,IAAMze,KAAKqc,WAAWnV,GACnF,CAOA8E,UAAU7Y,GACF6M,KAAKxM,eACLwM,KAAKxM,aAAa0gB,YAAc/gB,EAChC6M,KAAKxM,aAAa6L,MAAMC,QAAU,QAE1C,CAMAyd,aACQ/c,KAAKxM,eACLwM,KAAKxM,aAAa0gB,YAAc,GAChClU,KAAKxM,aAAa6L,MAAMC,QAAU,OAE1C,CAMAuM,WACI,OAA2B,EAApB7L,KAAKgc,MAAMrjB,MACtB,CAMA+lB,aACI1e,KAAKgc,MAAQ,GACbhc,KAAK0d,eAAe,CACxB,CAeAiB,iBAAiB/oB,GACb,IAQWgpB,EAAX,IAAWA,IARS,CAChB,CAAEC,MAAO,YAAa9e,KAAM,SAAU5M,QAAS,yBAA0B,EACzE,CAAE0rB,MAAO,mBAAoB9e,KAAM,SAAU5M,QAAS,4BAA6B,EACnF,CAAE0rB,MAAO,sBAAuB9e,KAAM,SAAU5M,QAAS,+BAAgC,EACzF,CAAE0rB,MAAO,YAAa9e,KAAM,SAAU5M,QAAS,2BAA4B,EAC3E,CAAE0rB,MAAO,WAAY9e,KAAM,SAAU5M,QAAS,0BAA2B,GAGvC,CAClC,IAAMgQ,EAAQnD,KAAK8e,eAAelpB,EAAUgpB,EAAWC,KAAK,EAC5D,GAAI,CAAC1b,GAAS,OAAOA,IAAUyb,EAAW7e,KACtC,MAAM,IAAI3N,MAAMwsB,EAAWzrB,OAAO,CAE1C,CAEA,GAAKyC,EAASM,YAAgBN,EAASM,sBAAsB6oB,KAI7D,OAAOnpB,EAHH,MAAM,IAAIxD,MAAM,6BAA6B,CAIrD,CASA0sB,eAAeE,EAAK3G,GAChB,OAAOA,EAAKha,MAAM,GAAG,EAAEif,OAAO,CAAC2B,EAAS5sB,IAAQ4sB,IAAU5sB,GAAM2sB,CAAG,CACvE,CAOAE,2BAA2BtpB,GACjBupB,EAAoBpsB,MAAMiN,KAAK2e,iBAAiB/oB,CAAQ,EAC9D,OAAaD,qBAAqBwpB,CAAiB,CACvD,CASApT,gCAAgClW,EAAQ9B,EAAW0B,GAE/C,IAAM2pB,EAAU,CACZC,mBAAoBrf,KAAKgc,MAAMrjB,OAC/B2mB,eAAgB,EAChBC,YAAa,GACb9mB,QAAS,CAAA,CACb,EAEA,IAAK/F,IAAIwU,EAAI,EAAGA,EAAIlH,KAAKgc,MAAMrjB,OAAQuO,CAAC,GAAI,CACxC,IAAMtR,EAAWoK,KAAKgc,MAAM9U,GAEtBpT,EAAS,CACX2E,QAAS,CAAA,EACT3F,SAAU,KACVD,MAAO,IACX,EAEA,IACI,IAAM2sB,EAAiB,CACnB3pB,OAAAA,EACA9B,UAAAA,EACA0B,UAAAA,EACAO,SAAUJ,EAASK,KAAKnB,KACxBoB,WAAYN,EAASK,KACrBG,gBAAiB8Q,CACrB,EAEMpU,EAAWC,MAAMiN,KAAKkf,qBAAqBM,CAAc,EAC/D1rB,EAAOhB,SAAWA,EAClBgB,EAAO2E,QAA8B,MAApB3F,EAAS0C,OAEtB1B,EAAO2E,SACP2mB,EAAQE,cAAc,EAI9B,CAFE,MAAOzsB,GACLiB,EAAOjB,MAAQA,EAAMM,OACzB,CAEAisB,EAAQG,YAAY/gB,KAAK1K,CAAM,CACnC,CAKA,OAHAsrB,EAAQ3mB,QAAU2mB,EAAQC,qBAAuBD,EAAQE,eACzDtf,KAAK0e,WAAW,EAETU,CACX,CACJ,OAEMnS,uBACFC,uBAAuB1I,GACnB,IAAMib,EAAiBzf,KAAKwE,GAE5B,GAA8B,YAA1B,OAAOib,EACP,MAAM,IAAIrtB,0BAA0BoS,cAAyB,EAKjE,OAFeib,EAAeC,KAAK1f,IAAI,EAAEzD,KAAK,CAGlD,CAEAojB,oBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCJ,CAEAC,wBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyDJ,CAEAC,oCACI;;;;;;CAOJ,CAEAC,iCACI;;;;;;;;;;CAWJ,CAEAC,sBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0EJ,CAEAC,qBACI;;;;;;;;;;;;;;;;;;;;;;;;;CA0BJ,CAEAC,mBACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyDJ,CAEAC,cACI;;;;;OAMJ,CAEAC,qBACI;;;;UAKJ,CAEAC,mBACI,MAAO,0EACX,CACAC,uBACI,MAAO,sJACX,CAEJ,OAEMlgB,iBACFmgB,eAAeC,GACX,IAAMC,EAAYxgB,KAAKugB,GAEvB,GAAyB,YAArB,OAAOC,EACP,MAAM,IAAIpuB,0BAA0BmuB,cAAoB,EAG5D,OAAOC,EAAUd,KAAK1f,IAAI,EAAEzD,KAAK,CACrC,CAEAkkB,mBAAmBF,GACf,OAAOvgB,KAAKsgB,QAAQC,CAAO,CAC/B,CAEAngB,oBAAoBmgB,GACVG,EAAM1gB,KAAKsgB,QAAQC,CAAO,EAChC,OAAOvgB,KAAK2gB,aAAaD,CAAG,CAChC,CAEAC,oBAAoBC,GACVvC,GAAQ,IAAIwC,aAAcC,OAAOF,CAAS,EAEhD,MAAO,6BADUG,KAAKxX,OAAOyX,aAAa,GAAG3C,CAAK,CAAC,CAEvD,CAEA7d,qBACI;;;OAIJ,CAEA4E,yBACI;;;OAIJ,CAEAlF,2BACI;;;;OAKJ,CAEAQ,2BACI;;;;;;;;;;;;OAaJ,CAEAD,yBACI;;;OAIJ,CAEAE,0BACI;;;OAIJ,CASAC,yBACI;;;;OAKJ,CAEAG,wBACI;;;OAIJ,CAEAC,yBACI;;;;;OAMJ,CAEAH,kCACI;;;OAIJ,CAEAI,uBACI;;;OAIJ,CAEAZ,0BACI;;;;OAKJ,CAEA4gB,oBACI;;;;;;;;;;;CAYJ,CAEA/b,iBACI;;;;CAKJ,CAEAC,kBACI;;;;CAKJ,CAEA7E,kBACI;;;;CAKJ,CAEAC,sBACI;;;;;;CAOJ,CAEAO,oBACI;mCAEJ,CACJ,OAEMoP,qBAEFpQ,cACIE,KAAKkhB,QAAQ,CACjB,CAEAC,aAEI,OAAO5F,UACX,CAEA2F,UACIlhB,KAAKohB,UAAU,EACfphB,KAAKqhB,QAAQ,CACjB,CAEAD,YACI,IAAME,EAAmB1kB,SAASwH,cAAc,MAAM,EAKhDmd,GAJND,EAAiBE,IAAM,aACvBF,EAAiBpnB,KAAO,+BACxB0C,SAAS6kB,KAAK9b,YAAY2b,CAAgB,EAEhB1kB,SAASwH,cAAc,MAAM,GAMjDsd,GALNH,EAAkBC,IAAM,aACxBD,EAAkBrnB,KAAO,4BACzBqnB,EAAkBI,YAAc,cAChC/kB,SAAS6kB,KAAK9b,YAAY4b,CAAiB,EAE1B3kB,SAASwH,cAAc,MAAM,GAC9Csd,EAASF,IAAM,aACfE,EAASxnB,KAAO,2EAChB0C,SAAS6kB,KAAK9b,YAAY+b,CAAQ,CACtC,CAEAL,UACI,IAAMhiB,EAAQzC,SAASwH,cAAc,OAAO,EAC5C/E,EAAMuiB,aAAa,KAAM,aAAa,EACtCviB,EAAM6U,YAAclU,KAAKmhB,WAAW,EACpCvkB,SAAS6kB,KAAK9b,YAAYtG,CAAK,CACnC,CACJ,CAEAzC,SAASilB,cAAc,IAAIC,YAAY,gBAAiB,CACpDC,OAAQ,CACJvpB,WAAW,IAAIsC,MAAOknB,YAAY,EAClC7uB,QAAS,iCACb,CACJ,CAAC,CAAC"} \ 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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;top:-80px;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;height:54px;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#review_content_button_text{color:#D5991A;margin-left:4px;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\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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","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","position","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/handlers.js b/js/src/handlers.js index 49c3069..8b1a4b1 100644 --- a/js/src/handlers.js +++ b/js/src/handlers.js @@ -303,3 +303,11 @@ function checkLogInOutButtonsVisible (){ if(el) el.style.display = 'none'; } } + +function changeSize(container){ + if(container && +localStorage.getItem('maximize')){ + container.classList.add('doboard_task_widget-container-maximize'); + } else if(container) { + container.classList.remove('doboard_task_widget-container-maximize'); + } +} diff --git a/js/src/widget.js b/js/src/widget.js index d82aafc..5f1c232 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -397,11 +397,7 @@ class CleanTalkWidgetDoboard { }); break; case 'all_issues': - if(container && +localStorage.getItem('maximize')){ - container.classList.add('doboard_task_widget-container-maximize'); - } else if(container) { - container.classList.remove('doboard_task_widget-container-maximize'); - } + changeSize(container); spotFixRemoveHighlights(); let issuesQuantityOnPage = 0; @@ -536,11 +532,7 @@ class CleanTalkWidgetDoboard { break; case 'concrete_issue': - if(container && +localStorage.getItem('maximize')){ - container.classList.add('doboard_task_widget-container-maximize'); - } else if(container) { - container.classList.remove('doboard_task_widget-container-maximize'); - } + changeSize(container); tasksFullDetails = await getTasksFullDetails(this.params, this.allTasksData, this.currentActiveTaskId); const taskDetails = await getTaskFullDetails(tasksFullDetails, this.currentActiveTaskId); // Update issue title in the interface From d0e8ac4dae55fa7f64c7b381d56db26e9736ee32 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Tue, 23 Dec 2025 03:55:15 +0400 Subject: [PATCH 12/20] Fix. Fix style --- dist/doboard-widget-bundle.js | 2 +- dist/doboard-widget-bundle.min.js | 2 +- dist/doboard-widget-bundle.min.js.map | 2 +- styles/doboard-widget.css | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index ae74cf1..9befafb 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -2672,7 +2672,7 @@ function spotFixRetrieveNodeFromPath(path) { return node; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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;top:-80px;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;height:54px;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#review_content_button_text{color:#D5991A;margin-left:4px;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}`; +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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;top:-80px;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;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index ff21a41..9945666 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -4,7 +4,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
- `}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` + `}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 4c8c63e..9bb3de9 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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;top:-80px;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;height:54px;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#review_content_button_text{color:#D5991A;margin-left:4px;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\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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","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","position","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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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;top:-80px;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;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#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\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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","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","position","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/styles/doboard-widget.css b/styles/doboard-widget.css index a87c75a..8023636 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -207,6 +207,7 @@ .wrap_review { width: 164px; + min-width: 164px; height: 54px; top: -100px; } @@ -223,7 +224,7 @@ #review_content_button_text { color: #D5991A; - margin-left: 4px; + margin-left: 6px; font-weight: 600; font-size: 14px; text-transform: none !important; From ab2d3c84ec395900f0e1bc4e8541e63a22f70376 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Tue, 23 Dec 2025 03:57:13 +0400 Subject: [PATCH 13/20] Fix. Fix top position --- dist/doboard-widget-bundle.js | 2 +- dist/doboard-widget-bundle.min.js | 2 +- dist/doboard-widget-bundle.min.js.map | 2 +- styles/doboard-widget.css | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 9befafb..c6ba9a2 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -2672,7 +2672,6 @@ function spotFixRetrieveNodeFromPath(path) { return node; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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;top:-80px;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;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} @@ -2851,6 +2850,7 @@ function storageProvidedTaskHasUnreadUpdates(taskId) { } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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;top:-80px;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}#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}`; /** * File uploader handler for managing file attachments with validation and upload capabilities */ diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 9945666..ab0e8bc 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -4,7 +4,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
- `}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` + `}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0img{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}`;class FileUploader{constructor(e){this.files=[],this.maxFileSize=5242880,this.maxTotalSize=26214400,this.maxFiles=5,this.allowedTypes=["image/jpeg","image/png","image/gif","application/pdf","text/plain","application/msword"],this.escapeHtmlHandler=e,this.SIZE_UNITS=["Bytes","KB","MB","GB"]}init(){this.initializeElements(),this.bindFilesInputChange()}initializeElements(){this.fileInput=document.getElementById("doboard_task_widget__file-upload__file-input-button"),this.fileList=document.getElementById("doboard_task_widget__file-upload__file-list"),this.uploaderWrapper=document.getElementById("doboard_task_widget__file-upload__wrapper"),this.errorMessage=document.getElementById("doboard_task_widget__file-upload__error"),this.fileInput&&this.fileList&&this.errorMessage&&!this.uploaderWrapper||console.warn("File uploader elements not found")}bindFilesInputChange(){this.fileInput&&this.fileInput.addEventListener("change",e=>this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 9bb3de9..9b7866b 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHN0RXZ0OndoZW49IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNC4wIChNYWNpbnRvc2gpIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuPRTtsAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAL0UExURUdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKGw/wAAAAAAAAAAAAAAAAAAAAAAAAAAAKOy/6Sw/gAAAAAAAAAAAAAAAIKPz6Kw/6Cw/6Kx/6Gw/6Gw/6Gw/6Gv/qCw/6Gw/6i0/6Oy/67D/6Gw/6Gx/6ez/6u9/6Gw/6Kx/6i5/624/6Cy/wAAAJ6r/6Oy/6W1/qCv/4aR1LPE/4eU0o+d3qGw/6Sy/6Ku/6Cv/KGw/6Cu/4WT1KKr/5up9Q8RGhodK7jI/4mY1K27/6Cv/8PW/7LE/6Gw/7nL/1RchUVLbbnN/0pXfBQVHjY5U2Vwm2ZwnyMmNrDB/6e2/629/7XG/6Kw/6Kw/67A/629/3N+vKe3/77Q/52r7HmEtrPE/6Oz8RgaKbTF/7TG/xgaKnaCtsLV/6Sv/7TI/wCv/6Gw/wAAAKCv/6e2/73O/6a1/6Oz/6u7/7zN/6q5/7fJ/629/7PD/wAAAQwNE5+u/7DA/6S0/7bH/7XG/6Gx/6i4/yUoOQQFBwICA7HC/7nL/zM4UouY3RcaJK+//y4ySL7Q/ygsPx8iME9WfTA1TXJ8sp2s9VxkjoSQ0RESGl9ok5up9XR/t213rRQWHkRKbJKf53mEwUxSeKGv+qy8/5Ce4jk+WQkKDjxBYCouQpSh6lZfiEFHZVpijJ6t/GFqmWdxoT5DY4eU1mp0qXiDvHyHxZak5n2KxlFZg8LU/32Kv4mV2ZSj7FBYgJGe50VLbS7TJ5EAAACrdFJOUwAPCsvhFe/y+w0C/fc8LUGd9SWvHnW1BPOTw/7NCbtcyNpxsr+4WVKbIETkCOiij0d96tQGEhCmijeFGGxw0Gp6qZhKxmbeYCtNG9NMgKzX5iduYwXl2GVVAZNEVKrs9opx5j/ZFcMIER77LlsYnDAbbDlLDH3+/v2wIlDxy8E95PP9un2PvJ1Pv2VX9kmOqeG89a2m+efFg2aYq9fPqexM0cHR6vWeMdh9ztTtu0oAAA1/SURBVHja7FxnWBPZGs5SQoAAocMiJEjv0qQEpMhCgAVRUFFEaYq9d7f3vb333u99ZpIAafTQ24Jg13XtfV3b7t1d7/65cyaTBiFMkknbZ94f6DOZnG/eOd/56jmhUEiQIEGCBAkSJEiQIEGCBAkSJEiQIEGCBAkS1o6cUAeH0FVWT8OeBaNg2Vs3D6dlMIZlTlZNJAtwoNHB3xyrJmKLMAgqYYch/9haM49YBximp1AoKcicOMRaOxFfCsXX2omgqhVWUmL1qoUtdpr1L3YV87vOyh1igYxHgZU7RATZiGLRvL8NwRZiuRy+DTwcARFHckYsB6l+MOyXasUEUjwichM8C1bEBcBwQMWKAs+E3AiPQGsLTVwSy1fDcxGQ5FPmYjWhSmA4IwnWgjhGuI0V0HDxj1N/bhrdz49OV79GzXexcBrMF1XefFCCd7ULpyTV0TG1hONS7Z0QqjJTLzItmEZRsvwxVzOyXDWshVjXLEaF/J7kIgulESEPEO0S3FK0WLPoBDvsxkURFkhjTxj2dOURvgvd6xvhid0ctsfSeCRi9jXSFd/9rvkBsm+UWdZ0YGs80mO+O6qaDx5srlK9spKBrXpXC1rkaAoIh2Ro+GxXTX1d7ZbSho2vvLKxoXRLbV19zWY5fR+ZfbaYRe+PPk9M9VwSO9eXboLmYFPp+l9vQ2+ojkG/6m8RNGxkqzxvdgq4rf49DSTk2P5ePeCSmod+OcgCXD0b9R0BL826vKF2uxTSju3HPgBq6Yz6lBJz8/BCfUKhuhVdV1m6EAsUnaXfQRZ9MOp7oszLIwpV8lD1dKOyCcILbhNCBdXNCi+z1kjQWD1P7dqBV6UQfnC5/9lPyUeNhRnrLIGoVkSqXtpbK9WFB9Av4fsUbzDOCvMlKqFzeGzYCOkMLvSvf+aitsus/kNVr9bt5kKQPkz47/yDZj5/wkQDDJULx1/ViwdYKIK//BXEXmbJUaKAA4hR8WSNGyG90Tn8xzeBOzKHEUazj5Uqy0MKGYBOwWEwJcvMFLerhHuVkIH46FMwYq7JFQvNoQjkweUJRsCYplYukIBQlQtkA2QwOiWnboIowbQ8XgYvT5lxv94NEcDko8dg1OUmJVKo9u72bpISQITLE02CANSkKSF4dcq0tknKhYiYEtFXsImdiZ1aaLKbEBoIpPxbIKI3HY9q4LvYioVOFA+I2/u/dmToapMRWaQ6IVs3QYRByv8M1O1MxSNDzd4fI44HMiWjYGxTVe0iEVk+igirm0AiUGvPBDJ4vml4pDggstASlq9XdM4bbUQS4Q7PAE+bYppiNSJqTaDr2kyfGBp8Y4jQGYGE0rPI8MUmIVIOeh9YY639soRLKBGp4Js5VQCjqJVbYohq6+kzvpRQHhBX9AlafU10M2LNbmV2vHpbjVZ4hOAJQXSL24FMNOJOqHnZK41AwtctfYUqB3pheSaz5E8ionlArb03ZETQwkr6El9CabglxKhNRcjL9uim0T9AhBPhCkCC1aEQFZPgRphGJarMRTCDivzFwpNdnYTzgKChM4iAt34arJS5ItGDABrL8xQD+vnkZjiBfZZJ2B7eesgIED5ApuPmCYqrt4+7YqOBp6FZCpMlHyspMnwpuFKsUknbYgwivLbbiIjXwPhLwyMVDW2WIdF9uLxP6x4fLq9n5ioLabuMwQNqFX2MiPgCa2vFRsTL5yU5XE8a0fLmf0GOvXp5cbHsvzuNQgTi30dEfLNTWSnPKZBvMtBn3b+A9SrhNPVvhygTht3GISICqfvIb9SsZhr2MIwXdOWxBGvqMzizPgBvB9tIUmocIhLg2/t/ry6Wg71XuyW68cjFZmNOZrBuDXJZRm7zUeMQ6XqEiBg7unmWZA5mPnUq4aGdF9g2WoOHr0AiE9mSqTEOD0h8ZxCGzz5onLtobeE5fQztiEe/kKnpIyc7Ral5n9QoPDpFj5AAZYy7T4P0TPTB4nXqe1DnUcYg5LMEVMnqjEGEyx3/L8jbp4fqNC5dqg59+XC0Tztf5Jmj2Of+207iaUjH+eIvgISHw7UaxXsU4i59LQW9o9XseTMS1NeyXvKlvC0mmAXE6xl+dv8tMP4lYd+H8/T1wX4v2lIcRICdc9aSCbhhdjDzd72CcQLz3JYhft+X9wZkox8WdZbOF8OCBhNjYR5sMI7W03YR8g2K/aevdwm6eESE8i3j/K4jd6ewgTu+FHChhqp55K+ClfG3FoBO8ZoF4nq5n4UHJ06PXuP3ClsN4MJt7Rvii6+fvo0lU/DAvWfDyMtpmvecBojwFz41ALYhZC+YopQVyrm09598ckrCl7S16EWCJx4WdR++OzkoH2/s7rPhISTPkVbOK32xal1Na8MAx1YwJ2Y5TZGodNy4//l5sUAkFrbgN8lSnnBIIOq7/PDjMcVAgzdmugVdUi5ihX81v2xXXM0HPyQfx3e2wGtxgUr22zHxfOb6VbFgWCIW8lq1B+o8oVgiGG47debTb6YGlENMnr7eK+pDtIrb8O4OLYId6XiODeAnAlTMO5TWrnySwUvTVx4+vXy1TyIQiCRd4jZhH4/Ha2np7m5B/u0TCsVdkh6BQCK8evnJuSu3O1Tew2D/3VGxYBxdbFsqm7VKxUcEp2opUJLzwzcH1SoTA2cnb508/fjJmTunHiAvv+2aeHwc4cRr5Z668+jpxXMnb01eGlD7xs2Rc0euCbpagC9pqtuxkEh8qoVrsavj4Hd/8KNLg3M3wQ90XJrqn5yYmB4ZmZ643T811jGg4ab+KxfODwnGeUDpGtbXrKMseKoM32IH5jdYNyJOFErV/nd+/L3+DlgntJ8deT7zdZugpw31q6V1jVW45OEzvws7xPmweWfdaz+5MjLV0b4wh5tTt54/Hr06zu+5xgOGrmH3vuN45aAOEcfmLjRE4eiZ52/9/qFjb4xeOHfy3nQ/oknq+tY+0DHWP33v5LkLX53nSfiicWGLbM/pvh3N+EVwcIYosqAxzoDNklXbPjj0/i9/8XPo/NejZz7/5MLMxYsXZy48eXpm9M55qEXcyx/u7WrrQ7Rpe8OH6+trtoKUQAfjEoc3aJSF8XaGFpCb9zZWHnr3Z2//+W9/7+3p6e2VSIaA7eprObppY9OW2vX/rmzc26z7sCvRWgLOwpDWxEp3RluP79jfWHPgxIYTBw7U7N9xfGuz/oMtRxOrBAJSXfNCx1RXUXxYYlk0sOKDTq1SrByUZ0HHO/QqB6kU6CzkUIQrVqArjCaqZGoWKEum+hz6dZMXsVlZZj2Mbp/FMqSIPautwDTTwYjYiHi6oW0FzY0eU2Ipk0FMo0fWeguQj+Xuk5uRYioSKXtUW2/lRGwQ9EhMVgZ+MYzsDKNvxg/k5DBUziwHl3kQZjXU2tNJIWXF9r5GIsEuLgtRPbNsl0Cs1ZyzYcDOM5PJIdQC2HCYZWlr1I4nE75hAIs8s+Pj1I9BU1nxmVnRXgYunBS2y9rMeBZVbWh6knG2cMjhqSHdo8WxPP0T1y7fw7bR4Ue0nGzYe5avTfT3ZM16OzJ4GtkggteWXuTPcteUwNKphbZhaf5l3llF4cVuGa4eHlElbHtwDNyeXRLl4eGa4VYcXpTlXeafFmZbSNX0/LAfy78oHUy2cY096OnGoBGMy6rMEDua9sw8wNmZRqO7Ozi4u9NoNOcA7XfTKoLSs1zQti0wLSHG5JGhvpMcbAXMTLOl0mCD4Ey1TcvMUV1qYJMenGFEIos0bma1YWdELE5PC1oW567L87vHLQtKS88Nd4uywSmIMCz0omJTOS7FzKzE9Pz4cp9Q2+TgQruKJCr4ORFqUoVdYXCybahPeXx+emIWs9iFkxqLe+qJhs6q6+SbEsgGP/DCDkzxddJrMRoDoFQJ636AU6+f3PGCcZUT9fO87nqdsNPzR5BAKYdunN9OQoe2MRURR3djHUxEJ3sxxVREKNn/b+dsdhIGojBqoZRCY4QIgokSLUyCJSSQEONGFiILExZKoj4GT8Y7ynRouVBiMr93c09YsOrH7XSmZ4Z2rLxx1SnV+opv1ynvr8Wnp/1ayZw1PsXDsh9UFRtEvZB0bKkGfnkYm2iYj14EbJctXBWyYMCGI6b7tPxzwXavPReFGMg9XonJnr4FZ+exYr+QCnjqN1DMLSjPdjtob7hYh1Ox38ad/UJELptyG33ZtAcquZBluirGn2D0xaB+ma7ZLW0Xkufe7l+CU8mFlDO36uzuTmH6Y26kt1dVKCTPrUVim12VXLgqw3++6GOT8eck/eLtWrt7b7cQmDsaq+bCA3bzA17M9rMeJ4UYyT1t4pN/5p1dWtq5hU73Dva9E53u10ln1809O/xetTyvleyHQckToz786uWevzGFzWa2wvAjeWOq80Lq7nOP8YqqIGsbMz7VnbnPPWXFwGJPyFaSq6xxY84XH+aN+Mtl7nmNf+UaH/gPb7I6vWDwnMqas3ruvxMr+QmOCYNVyTVN3mGj9KNvsFiIIbS3TnYeHiTrnq7BYnEwZ75LuQGDxSI3WP76e6BvsFhAg/0eJQbED6sQ4waLeWkZNVjUzm7UYHGHX4MGi35DNGawWFgwWCwsGCwWVgyWIAiCIAiCIAiCIAiCIAiCIAgU/gAyRDCHjvicJQAAAABJRU5ErkJggg==');`;\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;top:-80px;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;top:-100px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}#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\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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","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","position","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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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\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\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;top:-80px;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}#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 * 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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","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","position","slice","marker","insertText","idClass","cls","path","scrollIntoView","block","spans","affectedParents","Set","elementSelectionClassName","parent","tooltip","firstChild","removeChild","normalize","imageSelectionClassName","every","index","isInteger","imgNode","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","spotFixIsElementInRange","FILTER_ACCEPT","FILTER_REJECT","nextNode","startElement","spotFixGetElementFromNode","endElement","spotFixIsElementPartiallySelected","spotFixFindNearbyElements","elementRange","createRange","selectNode","compareBoundaryPoints","Range","START_TO_START","END_TO_END","elementRect","rangeRect","right","left","elements","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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/styles/doboard-widget.css b/styles/doboard-widget.css index 8023636..d709170 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -209,7 +209,6 @@ width: 164px; min-width: 164px; height: 54px; - top: -100px; } .wrap_review img { From cfb095e189f853d7ddb8359f617125e0c3844449 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Tue, 23 Dec 2025 04:03:08 +0400 Subject: [PATCH 14/20] Fix. Fix right position for mobile --- dist/doboard-widget-bundle.js | 2 +- dist/doboard-widget-bundle.min.js | 2 +- dist/doboard-widget-bundle.min.js.map | 2 +- styles/doboard-widget.css | 6 ++++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index c6ba9a2..a85157e 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -2672,6 +2672,7 @@ function spotFixRetrieveNodeFromPath(path) { return node; } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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;top:-80px;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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} @@ -2850,7 +2851,6 @@ function storageProvidedTaskHasUnreadUpdates(taskId) { } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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;top:-80px;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}#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}`; /** * File uploader handler for managing file attachments with validation and upload capabilities */ diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index ab0e8bc..6a5c81b 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -4,7 +4,7 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
- `}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0img{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}`;class FileUploader{constructor(e){this.files=[],this.maxFileSize=5242880,this.maxTotalSize=26214400,this.maxFiles=5,this.allowedTypes=["image/jpeg","image/png","image/gif","application/pdf","text/plain","application/msword"],this.escapeHtmlHandler=e,this.SIZE_UNITS=["Bytes","KB","MB","GB"]}init(){this.initializeElements(),this.bindFilesInputChange()}initializeElements(){this.fileInput=document.getElementById("doboard_task_widget__file-upload__file-input-button"),this.fileList=document.getElementById("doboard_task_widget__file-upload__file-list"),this.uploaderWrapper=document.getElementById("doboard_task_widget__file-upload__wrapper"),this.errorMessage=document.getElementById("doboard_task_widget__file-upload__error"),this.fileInput&&this.fileList&&this.errorMessage&&!this.uploaderWrapper||console.warn("File uploader elements not found")}bindFilesInputChange(){this.fileInput&&this.fileInput.addEventListener("change",e=>this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` + `}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 9b7866b..15fe53b 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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\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\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;top:-80px;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}#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 * 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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","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","position","slice","marker","insertText","idClass","cls","path","scrollIntoView","block","spans","affectedParents","Set","elementSelectionClassName","parent","tooltip","firstChild","removeChild","normalize","imageSelectionClassName","every","index","isInteger","imgNode","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","spotFixIsElementInRange","FILTER_ACCEPT","FILTER_REJECT","nextNode","startElement","spotFixGetElementFromNode","endElement","spotFixIsElementPartiallySelected","spotFixFindNearbyElements","elementRange","createRange","selectNode","compareBoundaryPoints","Range","START_TO_START","END_TO_END","elementRect","rangeRect","right","left","elements","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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;top:-80px;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\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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","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","position","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/styles/doboard-widget.css b/styles/doboard-widget.css index d709170..97f3daa 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -221,6 +221,12 @@ background-color: rgb(255, 255, 255); } +@media (max-width: 480px) { + .doboard_task_widget-wrap { + right: -20px; + } +} + #review_content_button_text { color: #D5991A; margin-left: 6px; From f76b7d85bdc766112da774c269dba1299c7d8683 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Tue, 23 Dec 2025 20:48:57 +0400 Subject: [PATCH 15/20] Upd. Add wrapped widget position customisation --- dist/doboard-widget-bundle.js | 20 +++++++++++++++----- dist/doboard-widget-bundle.min.js | 8 ++++---- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/loaders/SpotFixTemplatesLoader.js | 4 ++-- js/src/widget.js | 14 ++++++++++++-- styles/doboard-widget.css | 1 - 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index a85157e..5fc9d4f 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -910,6 +910,15 @@ class CleanTalkWidgetDoboard { let templateVariables = {}; + const config = window.SpotfixWidgetConfig; + const position = { + compact: '0vh', + short: '20vh', + regular: '45vh', + tall: '60vh', + extra: '85vh', + }; + switch (type) { case 'create_issue': templateName = 'create_issue'; @@ -928,12 +937,13 @@ class CleanTalkWidgetDoboard { if (storageGetWidgetIsClosed()) { return; } + templateName = 'wrap'; - templateVariables = {...this.srcVariables}; + templateVariables = {position: position[config?.verticalPosition] || position.compact, ...this.srcVariables}; break; case 'wrap_review': templateName = 'wrap_review'; - templateVariables = {...this.srcVariables}; + templateVariables = {position: position[config?.verticalPosition] || position.compact, ...this.srcVariables}; break; case 'all_issues': templateName = 'all_issues'; @@ -2672,7 +2682,6 @@ function spotFixRetrieveNodeFromPath(path) { return node; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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;top:-80px;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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} @@ -2851,6 +2860,7 @@ function storageProvidedTaskHasUnreadUpdates(taskId) { } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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}`; /** * File uploader handler for managing file attachments with validation and upload capabilities */ @@ -3544,7 +3554,7 @@ class SpotFixTemplatesLoader { static wrap() { return ` -
+
@@ -3553,7 +3563,7 @@ class SpotFixTemplatesLoader { static wrap_review() { return ` -`; diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 6a5c81b..20182ba 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={...this.srcVariables};break;case"wrap_review":t="wrap_review",l={...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var a=localStorage.getItem("spotfix_app_version");l={spotfixVersion:a?"Spotfix version "+a+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let i=this;e&&e.addEventListener("click",function(e,t=i){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` +
`}`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0img{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}`;class FileUploader{constructor(e){this.files=[],this.maxFileSize=5242880,this.maxTotalSize=26214400,this.maxFiles=5,this.allowedTypes=["image/jpeg","image/png","image/gif","application/pdf","text/plain","application/msword"],this.escapeHtmlHandler=e,this.SIZE_UNITS=["Bytes","KB","MB","GB"]}init(){this.initializeElements(),this.bindFilesInputChange()}initializeElements(){this.fileInput=document.getElementById("doboard_task_widget__file-upload__file-input-button"),this.fileList=document.getElementById("doboard_task_widget__file-upload__file-list"),this.uploaderWrapper=document.getElementById("doboard_task_widget__file-upload__wrapper"),this.errorMessage=document.getElementById("doboard_task_widget__file-upload__error"),this.fileInput&&this.fileList&&this.errorMessage&&!this.uploaderWrapper||console.warn("File uploader elements not found")}bindFilesInputChange(){this.fileInput&&this.fileInput.addEventListener("change",e=>this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
@@ -271,12 +271,12 @@ let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)
`}static wrap(){return` -
+
`}static wrap_review(){return` -`}static fixedHtml(){return'

Finished

'}static fixedTaskHtml(){return'

This issue already fixed

'}}class SpotFixSVGLoader{static loadSVG(e){var t=this[e];if("function"!=typeof t)throw new Error(`Template method '${e}' not found`);return t.call(this).trim()}static getAsRawSVG(e){return this.loadSVG(e)}static getAsDataURI(e){e=this.loadSVG(e);return this.svgToDataURI(e)}static svgToDataURI(e){e=(new TextEncoder).encode(e);return"data:image/svg+xml;base64,"+btoa(String.fromCharCode(...e))}static chevronBack(){return` diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 15fe53b..49e880c 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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 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 templateName = 'wrap';\r\n templateVariables = {...this.srcVariables};\r\n break;\r\n case 'wrap_review':\r\n templateName = 'wrap_review';\r\n templateVariables = {...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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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;top:-80px;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\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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","type_name","currentDomain","hostname","storageGetUserIsDefined","storageGetWidgetIsClosed","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","position","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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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\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\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 * 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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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 4e8425c..575845e 100644 --- a/js/src/loaders/SpotFixTemplatesLoader.js +++ b/js/src/loaders/SpotFixTemplatesLoader.js @@ -299,7 +299,7 @@ class SpotFixTemplatesLoader { static wrap() { return ` -
+
@@ -308,7 +308,7 @@ class SpotFixTemplatesLoader { static wrap_review() { return ` -`; diff --git a/js/src/widget.js b/js/src/widget.js index 5f1c232..de5d8eb 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -280,6 +280,15 @@ class CleanTalkWidgetDoboard { let templateVariables = {}; + const config = window.SpotfixWidgetConfig; + const position = { + compact: '0vh', + short: '20vh', + regular: '45vh', + tall: '60vh', + extra: '85vh', + }; + switch (type) { case 'create_issue': templateName = 'create_issue'; @@ -298,12 +307,13 @@ class CleanTalkWidgetDoboard { if (storageGetWidgetIsClosed()) { return; } + templateName = 'wrap'; - templateVariables = {...this.srcVariables}; + templateVariables = {position: position[config?.verticalPosition] || position.compact, ...this.srcVariables}; break; case 'wrap_review': templateName = 'wrap_review'; - templateVariables = {...this.srcVariables}; + templateVariables = {position: position[config?.verticalPosition] || position.compact, ...this.srcVariables}; break; case 'all_issues': templateName = 'all_issues'; diff --git a/styles/doboard-widget.css b/styles/doboard-widget.css index 97f3daa..46da394 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -180,7 +180,6 @@ .doboard_task_widget-wrap { box-shadow: none; position: fixed; - top: -80px; right: -50px; padding: 0; cursor: pointer; From d2bff2fe556c124e9cb0bd4f18cd83a29711f21b Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Thu, 25 Dec 2025 10:17:18 +0400 Subject: [PATCH 16/20] Fix. Corrected a typo --- dist/doboard-widget-bundle.js | 4 ++-- dist/doboard-widget-bundle.min.js | 2 +- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/api.js | 2 +- js/src/widget.js | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 5fc9d4f..270b824 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -185,7 +185,7 @@ const loginUserDoboard = async (email, password) => { } } -const jogoutUserDoboard = async (accountId) => { +const logoutUserDoboard = async (accountId) => { const sessionId = localStorage.getItem('spotfix_session_id'); if(sessionId && accountId) { const data = { @@ -1372,7 +1372,7 @@ class CleanTalkWidgetDoboard { }) || ''; document.querySelector('#doboard_task_widget-user_menu-logout_button')?.addEventListener('click', () => { - jogoutUserDoboard(this.params.accountId); + logoutUserDoboard(this.params.accountId); }) || ''; document.getElementById('addNewTaskButton')?.addEventListener('click', () => { diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 20182ba..9605b72 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,4 +1,4 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},jogoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index 49e880c..df582b8 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 jogoutUserDoboard = 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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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\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\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 * 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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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 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 }\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 localStorage.setItem('spotfix_app_version', 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\ttoggle.checked = true;\r\n\ttoggle.addEventListener('click', clickHandler);\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:\"http://localhost/\"}),\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: '',\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 || '';\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 jogoutUserDoboard(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 // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => {\r\n // const widget = document.querySelector('.doboard_task_widget-wrap');\r\n // widget.classList.add('hidden');\r\n // storageSetWidgetIsClosed(true);\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\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\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 * 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 logoDoBoardWhite() {\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","jogoutUserDoboard","removeItem","setItem","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","err","confirmUserEmail","pendingTaskRaw","pendingTask","JSON","parse","selectedText","description","selectedData","stringify","createdTask","handleCreateTask","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","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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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"} diff --git a/js/src/api.js b/js/src/api.js index 40b8e78..a8e3706 100644 --- a/js/src/api.js +++ b/js/src/api.js @@ -185,7 +185,7 @@ const loginUserDoboard = async (email, password) => { } } -const jogoutUserDoboard = async (accountId) => { +const logoutUserDoboard = async (accountId) => { const sessionId = localStorage.getItem('spotfix_session_id'); if(sessionId && accountId) { const data = { diff --git a/js/src/widget.js b/js/src/widget.js index de5d8eb..410fff3 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -742,7 +742,7 @@ class CleanTalkWidgetDoboard { }) || ''; document.querySelector('#doboard_task_widget-user_menu-logout_button')?.addEventListener('click', () => { - jogoutUserDoboard(this.params.accountId); + logoutUserDoboard(this.params.accountId); }) || ''; document.getElementById('addNewTaskButton')?.addEventListener('click', () => { From 298c5f4f8e1625fff11bcda9e053866bf0d8c074 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Thu, 25 Dec 2025 21:38:05 +0400 Subject: [PATCH 17/20] Fix. Edits based on comments from the review --- dist/doboard-widget-bundle.js | 33 +++++++++++++++------------ dist/doboard-widget-bundle.min.js | 4 ++-- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/api.js | 7 ++---- js/src/handlers.js | 8 ++++--- js/src/storage.js | 10 ++++++++ js/src/widget.js | 8 +------ 7 files changed, 39 insertions(+), 33 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 270b824..52874f1 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -194,10 +194,7 @@ const logoutUserDoboard = async (accountId) => { const result = await spotfixApiCall(data, 'user_unauthorize', accountId); if(result.operation_status === 'SUCCESS') { - localStorage.removeItem('spotfix_email'); - localStorage.removeItem('spotfix_session_id'); - localStorage.removeItem('spotfix_user_id'); - localStorage.setItem('spotfix_widget_is_closed', '1'); + clearLocalstorageOnLogout(); } } } @@ -303,7 +300,7 @@ const getReleaseVersion = async () => { const data = await res.json(); if (data.length > 0 && data[0].tag_name) { - localStorage.setItem('spotfix_app_version', data[0].tag_name); + storageSaveSpotfixVersion(data[0].tag_name); return data[0].tag_name; } @@ -604,15 +601,17 @@ function setToggleStatus(rootElement){ }, 300); }; const toggle = document.getElementById('widget_visibility'); - toggle.checked = true; - toggle.addEventListener('click', clickHandler); + if(toggle) { + toggle.checked = true; + toggle.addEventListener('click', clickHandler); + } } function checkLogInOutButtonsVisible (){ if(!localStorage.getItem('spotfix_session_id')) { const el = document .getElementById('doboard_task_widget-user_menu-logout_button') - .closest('.doboard_task_widget-user_menu-item'); + ?.closest('.doboard_task_widget-user_menu-item'); if(el) el.style.display = 'none'; } else { const el = document.getElementById('doboard_task_widget-user_menu-signlog_button'); @@ -842,7 +841,7 @@ class CleanTalkWidgetDoboard { projectToken: this.params.projectToken, projectId: this.params.projectId, accountId: this.params.accountId, - taskMeta: JSON.stringify(this.selectedData ? this.selectedData : {pageURL:"http://localhost/"}), + taskMeta: JSON.stringify(this.selectedData ? this.selectedData : { pageURL: window.location.href }), }; if ( userEmail ) { @@ -1399,12 +1398,6 @@ class CleanTalkWidgetDoboard { this.createWidgetElement(this.type_name) }) || ''; - // document.querySelector('#doboard_task_widget-task_count')?.addEventListener('click', () => { - // const widget = document.querySelector('.doboard_task_widget-wrap'); - // widget.classList.add('hidden'); - // storageSetWidgetIsClosed(true); - // }) || ''; - return widgetContainer; } @@ -2859,6 +2852,16 @@ function storageProvidedTaskHasUnreadUpdates(taskId) { return storedUnread.includes(taskId.toString()); } +function storageSaveSpotfixVersion (version) { + localStorage.setItem('spotfix_app_version', `${version}`); +} + +function clearLocalstorageOnLogout () { + localStorage.removeItem('spotfix_email'); + localStorage.removeItem('spotfix_session_id'); + localStorage.removeItem('spotfix_user_id'); + localStorage.setItem('spotfix_widget_is_closed', '1'); +} let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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}`; /** diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 9605b72..376cee2 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&(localStorage.removeItem("spotfix_email"),localStorage.removeItem("spotfix_session_id"),localStorage.removeItem("spotfix_user_id"),localStorage.setItem("spotfix_widget_is_closed","1"))},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)})}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button").closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:"http://localhost/"})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{jogoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&clearLocalstorageOnLogout()},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


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


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e&&(e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)}))}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button")?.closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:window.location.href})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{logoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHN0RXZ0OndoZW49IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNC4wIChNYWNpbnRvc2gpIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuPRTtsAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAL0UExURUdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKGw/wAAAAAAAAAAAAAAAAAAAAAAAAAAAKOy/6Sw/gAAAAAAAAAAAAAAAIKPz6Kw/6Cw/6Kx/6Gw/6Gw/6Gw/6Gv/qCw/6Gw/6i0/6Oy/67D/6Gw/6Gx/6ez/6u9/6Gw/6Kx/6i5/624/6Cy/wAAAJ6r/6Oy/6W1/qCv/4aR1LPE/4eU0o+d3qGw/6Sy/6Ku/6Cv/KGw/6Cu/4WT1KKr/5up9Q8RGhodK7jI/4mY1K27/6Cv/8PW/7LE/6Gw/7nL/1RchUVLbbnN/0pXfBQVHjY5U2Vwm2ZwnyMmNrDB/6e2/629/7XG/6Kw/6Kw/67A/629/3N+vKe3/77Q/52r7HmEtrPE/6Oz8RgaKbTF/7TG/xgaKnaCtsLV/6Sv/7TI/wCv/6Gw/wAAAKCv/6e2/73O/6a1/6Oz/6u7/7zN/6q5/7fJ/629/7PD/wAAAQwNE5+u/7DA/6S0/7bH/7XG/6Gx/6i4/yUoOQQFBwICA7HC/7nL/zM4UouY3RcaJK+//y4ySL7Q/ygsPx8iME9WfTA1TXJ8sp2s9VxkjoSQ0RESGl9ok5up9XR/t213rRQWHkRKbJKf53mEwUxSeKGv+qy8/5Ce4jk+WQkKDjxBYCouQpSh6lZfiEFHZVpijJ6t/GFqmWdxoT5DY4eU1mp0qXiDvHyHxZak5n2KxlFZg8LU/32Kv4mV2ZSj7FBYgJGe50VLbS7TJ5EAAACrdFJOUwAPCsvhFe/y+w0C/fc8LUGd9SWvHnW1BPOTw/7NCbtcyNpxsr+4WVKbIETkCOiij0d96tQGEhCmijeFGGxw0Gp6qZhKxmbeYCtNG9NMgKzX5iduYwXl2GVVAZNEVKrs9opx5j/ZFcMIER77LlsYnDAbbDlLDH3+/v2wIlDxy8E95PP9un2PvJ1Pv2VX9kmOqeG89a2m+efFg2aYq9fPqexM0cHR6vWeMdh9ztTtu0oAAA1/SURBVHja7FxnWBPZGs5SQoAAocMiJEjv0qQEpMhCgAVRUFFEaYq9d7f3vb333u99ZpIAafTQ24Jg13XtfV3b7t1d7/65cyaTBiFMkknbZ94f6DOZnG/eOd/56jmhUEiQIEGCBAkSJEiQIEGCBAkSJEiQIEGCBAkS1o6cUAeH0FVWT8OeBaNg2Vs3D6dlMIZlTlZNJAtwoNHB3xyrJmKLMAgqYYch/9haM49YBximp1AoKcicOMRaOxFfCsXX2omgqhVWUmL1qoUtdpr1L3YV87vOyh1igYxHgZU7RATZiGLRvL8NwRZiuRy+DTwcARFHckYsB6l+MOyXasUEUjwichM8C1bEBcBwQMWKAs+E3AiPQGsLTVwSy1fDcxGQ5FPmYjWhSmA4IwnWgjhGuI0V0HDxj1N/bhrdz49OV79GzXexcBrMF1XefFCCd7ULpyTV0TG1hONS7Z0QqjJTLzItmEZRsvwxVzOyXDWshVjXLEaF/J7kIgulESEPEO0S3FK0WLPoBDvsxkURFkhjTxj2dOURvgvd6xvhid0ctsfSeCRi9jXSFd/9rvkBsm+UWdZ0YGs80mO+O6qaDx5srlK9spKBrXpXC1rkaAoIh2Ro+GxXTX1d7ZbSho2vvLKxoXRLbV19zWY5fR+ZfbaYRe+PPk9M9VwSO9eXboLmYFPp+l9vQ2+ojkG/6m8RNGxkqzxvdgq4rf49DSTk2P5ePeCSmod+OcgCXD0b9R0BL826vKF2uxTSju3HPgBq6Yz6lBJz8/BCfUKhuhVdV1m6EAsUnaXfQRZ9MOp7oszLIwpV8lD1dKOyCcILbhNCBdXNCi+z1kjQWD1P7dqBV6UQfnC5/9lPyUeNhRnrLIGoVkSqXtpbK9WFB9Av4fsUbzDOCvMlKqFzeGzYCOkMLvSvf+aitsus/kNVr9bt5kKQPkz47/yDZj5/wkQDDJULx1/ViwdYKIK//BXEXmbJUaKAA4hR8WSNGyG90Tn8xzeBOzKHEUazj5Uqy0MKGYBOwWEwJcvMFLerhHuVkIH46FMwYq7JFQvNoQjkweUJRsCYplYukIBQlQtkA2QwOiWnboIowbQ8XgYvT5lxv94NEcDko8dg1OUmJVKo9u72bpISQITLE02CANSkKSF4dcq0tknKhYiYEtFXsImdiZ1aaLKbEBoIpPxbIKI3HY9q4LvYioVOFA+I2/u/dmToapMRWaQ6IVs3QYRByv8M1O1MxSNDzd4fI44HMiWjYGxTVe0iEVk+igirm0AiUGvPBDJ4vml4pDggstASlq9XdM4bbUQS4Q7PAE+bYppiNSJqTaDr2kyfGBp8Y4jQGYGE0rPI8MUmIVIOeh9YY639soRLKBGp4Js5VQCjqJVbYohq6+kzvpRQHhBX9AlafU10M2LNbmV2vHpbjVZ4hOAJQXSL24FMNOJOqHnZK41AwtctfYUqB3pheSaz5E8ionlArb03ZETQwkr6El9CabglxKhNRcjL9uim0T9AhBPhCkCC1aEQFZPgRphGJarMRTCDivzFwpNdnYTzgKChM4iAt34arJS5ItGDABrL8xQD+vnkZjiBfZZJ2B7eesgIED5ApuPmCYqrt4+7YqOBp6FZCpMlHyspMnwpuFKsUknbYgwivLbbiIjXwPhLwyMVDW2WIdF9uLxP6x4fLq9n5ioLabuMwQNqFX2MiPgCa2vFRsTL5yU5XE8a0fLmf0GOvXp5cbHsvzuNQgTi30dEfLNTWSnPKZBvMtBn3b+A9SrhNPVvhygTht3GISICqfvIb9SsZhr2MIwXdOWxBGvqMzizPgBvB9tIUmocIhLg2/t/ry6Wg71XuyW68cjFZmNOZrBuDXJZRm7zUeMQ6XqEiBg7unmWZA5mPnUq4aGdF9g2WoOHr0AiE9mSqTEOD0h8ZxCGzz5onLtobeE5fQztiEe/kKnpIyc7Ral5n9QoPDpFj5AAZYy7T4P0TPTB4nXqe1DnUcYg5LMEVMnqjEGEyx3/L8jbp4fqNC5dqg59+XC0Tztf5Jmj2Of+207iaUjH+eIvgISHw7UaxXsU4i59LQW9o9XseTMS1NeyXvKlvC0mmAXE6xl+dv8tMP4lYd+H8/T1wX4v2lIcRICdc9aSCbhhdjDzd72CcQLz3JYhft+X9wZkox8WdZbOF8OCBhNjYR5sMI7W03YR8g2K/aevdwm6eESE8i3j/K4jd6ewgTu+FHChhqp55K+ClfG3FoBO8ZoF4nq5n4UHJ06PXuP3ClsN4MJt7Rvii6+fvo0lU/DAvWfDyMtpmvecBojwFz41ALYhZC+YopQVyrm09598ckrCl7S16EWCJx4WdR++OzkoH2/s7rPhISTPkVbOK32xal1Na8MAx1YwJ2Y5TZGodNy4//l5sUAkFrbgN8lSnnBIIOq7/PDjMcVAgzdmugVdUi5ihX81v2xXXM0HPyQfx3e2wGtxgUr22zHxfOb6VbFgWCIW8lq1B+o8oVgiGG47debTb6YGlENMnr7eK+pDtIrb8O4OLYId6XiODeAnAlTMO5TWrnySwUvTVx4+vXy1TyIQiCRd4jZhH4/Ha2np7m5B/u0TCsVdkh6BQCK8evnJuSu3O1Tew2D/3VGxYBxdbFsqm7VKxUcEp2opUJLzwzcH1SoTA2cnb508/fjJmTunHiAvv+2aeHwc4cRr5Z668+jpxXMnb01eGlD7xs2Rc0euCbpagC9pqtuxkEh8qoVrsavj4Hd/8KNLg3M3wQ90XJrqn5yYmB4ZmZ643T811jGg4ab+KxfODwnGeUDpGtbXrKMseKoM32IH5jdYNyJOFErV/nd+/L3+DlgntJ8deT7zdZugpw31q6V1jVW45OEzvws7xPmweWfdaz+5MjLV0b4wh5tTt54/Hr06zu+5xgOGrmH3vuN45aAOEcfmLjRE4eiZ52/9/qFjb4xeOHfy3nQ/oknq+tY+0DHWP33v5LkLX53nSfiicWGLbM/pvh3N+EVwcIYosqAxzoDNklXbPjj0/i9/8XPo/NejZz7/5MLMxYsXZy48eXpm9M55qEXcyx/u7WrrQ7Rpe8OH6+trtoKUQAfjEoc3aJSF8XaGFpCb9zZWHnr3Z2//+W9/7+3p6e2VSIaA7eprObppY9OW2vX/rmzc26z7sCvRWgLOwpDWxEp3RluP79jfWHPgxIYTBw7U7N9xfGuz/oMtRxOrBAJSXfNCx1RXUXxYYlk0sOKDTq1SrByUZ0HHO/QqB6kU6CzkUIQrVqArjCaqZGoWKEum+hz6dZMXsVlZZj2Mbp/FMqSIPautwDTTwYjYiHi6oW0FzY0eU2Ipk0FMo0fWeguQj+Xuk5uRYioSKXtUW2/lRGwQ9EhMVgZ+MYzsDKNvxg/k5DBUziwHl3kQZjXU2tNJIWXF9r5GIsEuLgtRPbNsl0Cs1ZyzYcDOM5PJIdQC2HCYZWlr1I4nE75hAIs8s+Pj1I9BU1nxmVnRXgYunBS2y9rMeBZVbWh6knG2cMjhqSHdo8WxPP0T1y7fw7bR4Ue0nGzYe5avTfT3ZM16OzJ4GtkggteWXuTPcteUwNKphbZhaf5l3llF4cVuGa4eHlElbHtwDNyeXRLl4eGa4VYcXpTlXeafFmZbSNX0/LAfy78oHUy2cY096OnGoBGMy6rMEDua9sw8wNmZRqO7Ozi4u9NoNOcA7XfTKoLSs1zQti0wLSHG5JGhvpMcbAXMTLOl0mCD4Ey1TcvMUV1qYJMenGFEIos0bma1YWdELE5PC1oW567L87vHLQtKS88Nd4uywSmIMCz0omJTOS7FzKzE9Pz4cp9Q2+TgQruKJCr4ORFqUoVdYXCybahPeXx+emIWs9iFkxqLe+qJhs6q6+SbEsgGP/DCDkzxddJrMRoDoFQJ636AU6+f3PGCcZUT9fO87nqdsNPzR5BAKYdunN9OQoe2MRURR3djHUxEJ3sxxVREKNn/b+dsdhIGojBqoZRCY4QIgokSLUyCJSSQEONGFiILExZKoj4GT8Y7ynRouVBiMr93c09YsOrH7XSmZ4Z2rLxx1SnV+opv1ynvr8Wnp/1ayZw1PsXDsh9UFRtEvZB0bKkGfnkYm2iYj14EbJctXBWyYMCGI6b7tPxzwXavPReFGMg9XonJnr4FZ+exYr+QCnjqN1DMLSjPdjtob7hYh1Ox38ad/UJELptyG33ZtAcquZBluirGn2D0xaB+ma7ZLW0Xkufe7l+CU8mFlDO36uzuTmH6Y26kt1dVKCTPrUVim12VXLgqw3++6GOT8eck/eLtWrt7b7cQmDsaq+bCA3bzA17M9rMeJ4UYyT1t4pN/5p1dWtq5hU73Dva9E53u10ln1809O/xetTyvleyHQckToz786uWevzGFzWa2wvAjeWOq80Lq7nOP8YqqIGsbMz7VnbnPPWXFwGJPyFaSq6xxY84XH+aN+Mtl7nmNf+UaH/gPb7I6vWDwnMqas3ruvxMr+QmOCYNVyTVN3mGj9KNvsFiIIbS3TnYeHiTrnq7BYnEwZ75LuQGDxSI3WP76e6BvsFhAg/0eJQbED6sQ4waLeWkZNVjUzm7UYHGHX4MGi35DNGawWFgwWCwsGCwWVgyWIAiCIAiCIAiCIAiCIAiCIAgU/gAyRDCHjvicJQAAAABJRU5ErkJggg==');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&clearLocalstorageOnLogout()},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e&&(e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)}))}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button")?.closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:window.location.href})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{logoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let spotFixCSS=`.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:"";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:"";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:"";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:"wght" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:""}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`,SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0img{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}`;class FileUploader{constructor(e){this.files=[],this.maxFileSize=5242880,this.maxTotalSize=26214400,this.maxFiles=5,this.allowedTypes=["image/jpeg","image/png","image/gif","application/pdf","text/plain","application/msword"],this.escapeHtmlHandler=e,this.SIZE_UNITS=["Bytes","KB","MB","GB"]}init(){this.initializeElements(),this.bindFilesInputChange()}initializeElements(){this.fileInput=document.getElementById("doboard_task_widget__file-upload__file-input-button"),this.fileList=document.getElementById("doboard_task_widget__file-upload__file-list"),this.uploaderWrapper=document.getElementById("doboard_task_widget__file-upload__wrapper"),this.errorMessage=document.getElementById("doboard_task_widget__file-upload__error"),this.fileInput&&this.fileList&&this.errorMessage&&!this.uploaderWrapper||console.warn("File uploader elements not found")}bindFilesInputChange(){this.fileInput&&this.fileInput.addEventListener("change",e=>this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` + `}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index fdc4552..f0420ad 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: '',\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 || '';\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\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\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 * 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 logoDoBoardWhite() {\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","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","id","spotFixCSS","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: '',\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 || '';\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,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMtOGVlZi00ZDUxLWJhNDEtZDk5M2U2ZjYzZjEyIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHN0RXZ0OndoZW49IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNC4wIChNYWNpbnRvc2gpIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuPRTtsAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAL0UExURUdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKGw/wAAAAAAAAAAAAAAAAAAAAAAAAAAAKOy/6Sw/gAAAAAAAAAAAAAAAIKPz6Kw/6Cw/6Kx/6Gw/6Gw/6Gw/6Gv/qCw/6Gw/6i0/6Oy/67D/6Gw/6Gx/6ez/6u9/6Gw/6Kx/6i5/624/6Cy/wAAAJ6r/6Oy/6W1/qCv/4aR1LPE/4eU0o+d3qGw/6Sy/6Ku/6Cv/KGw/6Cu/4WT1KKr/5up9Q8RGhodK7jI/4mY1K27/6Cv/8PW/7LE/6Gw/7nL/1RchUVLbbnN/0pXfBQVHjY5U2Vwm2ZwnyMmNrDB/6e2/629/7XG/6Kw/6Kw/67A/629/3N+vKe3/77Q/52r7HmEtrPE/6Oz8RgaKbTF/7TG/xgaKnaCtsLV/6Sv/7TI/wCv/6Gw/wAAAKCv/6e2/73O/6a1/6Oz/6u7/7zN/6q5/7fJ/629/7PD/wAAAQwNE5+u/7DA/6S0/7bH/7XG/6Gx/6i4/yUoOQQFBwICA7HC/7nL/zM4UouY3RcaJK+//y4ySL7Q/ygsPx8iME9WfTA1TXJ8sp2s9VxkjoSQ0RESGl9ok5up9XR/t213rRQWHkRKbJKf53mEwUxSeKGv+qy8/5Ce4jk+WQkKDjxBYCouQpSh6lZfiEFHZVpijJ6t/GFqmWdxoT5DY4eU1mp0qXiDvHyHxZak5n2KxlFZg8LU/32Kv4mV2ZSj7FBYgJGe50VLbS7TJ5EAAACrdFJOUwAPCsvhFe/y+w0C/fc8LUGd9SWvHnW1BPOTw/7NCbtcyNpxsr+4WVKbIETkCOiij0d96tQGEhCmijeFGGxw0Gp6qZhKxmbeYCtNG9NMgKzX5iduYwXl2GVVAZNEVKrs9opx5j/ZFcMIER77LlsYnDAbbDlLDH3+/v2wIlDxy8E95PP9un2PvJ1Pv2VX9kmOqeG89a2m+efFg2aYq9fPqexM0cHR6vWeMdh9ztTtu0oAAA1/SURBVHja7FxnWBPZGs5SQoAAocMiJEjv0qQEpMhCgAVRUFFEaYq9d7f3vb333u99ZpIAafTQ24Jg13XtfV3b7t1d7/65cyaTBiFMkknbZ94f6DOZnG/eOd/56jmhUEiQIEGCBAkSJEiQIEGCBAkSJEiQIEGCBAkS1o6cUAeH0FVWT8OeBaNg2Vs3D6dlMIZlTlZNJAtwoNHB3xyrJmKLMAgqYYch/9haM49YBximp1AoKcicOMRaOxFfCsXX2omgqhVWUmL1qoUtdpr1L3YV87vOyh1igYxHgZU7RATZiGLRvL8NwRZiuRy+DTwcARFHckYsB6l+MOyXasUEUjwichM8C1bEBcBwQMWKAs+E3AiPQGsLTVwSy1fDcxGQ5FPmYjWhSmA4IwnWgjhGuI0V0HDxj1N/bhrdz49OV79GzXexcBrMF1XefFCCd7ULpyTV0TG1hONS7Z0QqjJTLzItmEZRsvwxVzOyXDWshVjXLEaF/J7kIgulESEPEO0S3FK0WLPoBDvsxkURFkhjTxj2dOURvgvd6xvhid0ctsfSeCRi9jXSFd/9rvkBsm+UWdZ0YGs80mO+O6qaDx5srlK9spKBrXpXC1rkaAoIh2Ro+GxXTX1d7ZbSho2vvLKxoXRLbV19zWY5fR+ZfbaYRe+PPk9M9VwSO9eXboLmYFPp+l9vQ2+ojkG/6m8RNGxkqzxvdgq4rf49DSTk2P5ePeCSmod+OcgCXD0b9R0BL826vKF2uxTSju3HPgBq6Yz6lBJz8/BCfUKhuhVdV1m6EAsUnaXfQRZ9MOp7oszLIwpV8lD1dKOyCcILbhNCBdXNCi+z1kjQWD1P7dqBV6UQfnC5/9lPyUeNhRnrLIGoVkSqXtpbK9WFB9Av4fsUbzDOCvMlKqFzeGzYCOkMLvSvf+aitsus/kNVr9bt5kKQPkz47/yDZj5/wkQDDJULx1/ViwdYKIK//BXEXmbJUaKAA4hR8WSNGyG90Tn8xzeBOzKHEUazj5Uqy0MKGYBOwWEwJcvMFLerhHuVkIH46FMwYq7JFQvNoQjkweUJRsCYplYukIBQlQtkA2QwOiWnboIowbQ8XgYvT5lxv94NEcDko8dg1OUmJVKo9u72bpISQITLE02CANSkKSF4dcq0tknKhYiYEtFXsImdiZ1aaLKbEBoIpPxbIKI3HY9q4LvYioVOFA+I2/u/dmToapMRWaQ6IVs3QYRByv8M1O1MxSNDzd4fI44HMiWjYGxTVe0iEVk+igirm0AiUGvPBDJ4vml4pDggstASlq9XdM4bbUQS4Q7PAE+bYppiNSJqTaDr2kyfGBp8Y4jQGYGE0rPI8MUmIVIOeh9YY639soRLKBGp4Js5VQCjqJVbYohq6+kzvpRQHhBX9AlafU10M2LNbmV2vHpbjVZ4hOAJQXSL24FMNOJOqHnZK41AwtctfYUqB3pheSaz5E8ionlArb03ZETQwkr6El9CabglxKhNRcjL9uim0T9AhBPhCkCC1aEQFZPgRphGJarMRTCDivzFwpNdnYTzgKChM4iAt34arJS5ItGDABrL8xQD+vnkZjiBfZZJ2B7eesgIED5ApuPmCYqrt4+7YqOBp6FZCpMlHyspMnwpuFKsUknbYgwivLbbiIjXwPhLwyMVDW2WIdF9uLxP6x4fLq9n5ioLabuMwQNqFX2MiPgCa2vFRsTL5yU5XE8a0fLmf0GOvXp5cbHsvzuNQgTi30dEfLNTWSnPKZBvMtBn3b+A9SrhNPVvhygTht3GISICqfvIb9SsZhr2MIwXdOWxBGvqMzizPgBvB9tIUmocIhLg2/t/ry6Wg71XuyW68cjFZmNOZrBuDXJZRm7zUeMQ6XqEiBg7unmWZA5mPnUq4aGdF9g2WoOHr0AiE9mSqTEOD0h8ZxCGzz5onLtobeE5fQztiEe/kKnpIyc7Ral5n9QoPDpFj5AAZYy7T4P0TPTB4nXqe1DnUcYg5LMEVMnqjEGEyx3/L8jbp4fqNC5dqg59+XC0Tztf5Jmj2Of+207iaUjH+eIvgISHw7UaxXsU4i59LQW9o9XseTMS1NeyXvKlvC0mmAXE6xl+dv8tMP4lYd+H8/T1wX4v2lIcRICdc9aSCbhhdjDzd72CcQLz3JYhft+X9wZkox8WdZbOF8OCBhNjYR5sMI7W03YR8g2K/aevdwm6eESE8i3j/K4jd6ewgTu+FHChhqp55K+ClfG3FoBO8ZoF4nq5n4UHJ06PXuP3ClsN4MJt7Rvii6+fvo0lU/DAvWfDyMtpmvecBojwFz41ALYhZC+YopQVyrm09598ckrCl7S16EWCJx4WdR++OzkoH2/s7rPhISTPkVbOK32xal1Na8MAx1YwJ2Y5TZGodNy4//l5sUAkFrbgN8lSnnBIIOq7/PDjMcVAgzdmugVdUi5ihX81v2xXXM0HPyQfx3e2wGtxgUr22zHxfOb6VbFgWCIW8lq1B+o8oVgiGG47debTb6YGlENMnr7eK+pDtIrb8O4OLYId6XiODeAnAlTMO5TWrnySwUvTVx4+vXy1TyIQiCRd4jZhH4/Ha2np7m5B/u0TCsVdkh6BQCK8evnJuSu3O1Tew2D/3VGxYBxdbFsqm7VKxUcEp2opUJLzwzcH1SoTA2cnb508/fjJmTunHiAvv+2aeHwc4cRr5Z668+jpxXMnb01eGlD7xs2Rc0euCbpagC9pqtuxkEh8qoVrsavj4Hd/8KNLg3M3wQ90XJrqn5yYmB4ZmZ643T811jGg4ab+KxfODwnGeUDpGtbXrKMseKoM32IH5jdYNyJOFErV/nd+/L3+DlgntJ8deT7zdZugpw31q6V1jVW45OEzvws7xPmweWfdaz+5MjLV0b4wh5tTt54/Hr06zu+5xgOGrmH3vuN45aAOEcfmLjRE4eiZ52/9/qFjb4xeOHfy3nQ/oknq+tY+0DHWP33v5LkLX53nSfiicWGLbM/pvh3N+EVwcIYosqAxzoDNklXbPjj0/i9/8XPo/NejZz7/5MLMxYsXZy48eXpm9M55qEXcyx/u7WrrQ7Rpe8OH6+trtoKUQAfjEoc3aJSF8XaGFpCb9zZWHnr3Z2//+W9/7+3p6e2VSIaA7eprObppY9OW2vX/rmzc26z7sCvRWgLOwpDWxEp3RluP79jfWHPgxIYTBw7U7N9xfGuz/oMtRxOrBAJSXfNCx1RXUXxYYlk0sOKDTq1SrByUZ0HHO/QqB6kU6CzkUIQrVqArjCaqZGoWKEum+hz6dZMXsVlZZj2Mbp/FMqSIPautwDTTwYjYiHi6oW0FzY0eU2Ipk0FMo0fWeguQj+Xuk5uRYioSKXtUW2/lRGwQ9EhMVgZ+MYzsDKNvxg/k5DBUziwHl3kQZjXU2tNJIWXF9r5GIsEuLgtRPbNsl0Cs1ZyzYcDOM5PJIdQC2HCYZWlr1I4nE75hAIs8s+Pj1I9BU1nxmVnRXgYunBS2y9rMeBZVbWh6knG2cMjhqSHdo8WxPP0T1y7fw7bR4Ue0nGzYe5avTfT3ZM16OzJ4GtkggteWXuTPcteUwNKphbZhaf5l3llF4cVuGa4eHlElbHtwDNyeXRLl4eGa4VYcXpTlXeafFmZbSNX0/LAfy78oHUy2cY096OnGoBGMy6rMEDua9sw8wNmZRqO7Ozi4u9NoNOcA7XfTKoLSs1zQti0wLSHG5JGhvpMcbAXMTLOl0mCD4Ey1TcvMUV1qYJMenGFEIos0bma1YWdELE5PC1oW567L87vHLQtKS88Nd4uywSmIMCz0omJTOS7FzKzE9Pz4cp9Q2+TgQruKJCr4ORFqUoVdYXCybahPeXx+emIWs9iFkxqLe+qJhs6q6+SbEsgGP/DCDkzxddJrMRoDoFQJ636AU6+f3PGCcZUT9fO87nqdsNPzR5BAKYdunN9OQoe2MRURR3djHUxEJ3sxxVREKNn/b+dsdhIGojBqoZRCY4QIgokSLUyCJSSQEONGFiILExZKoj4GT8Y7ynRouVBiMr93c09YsOrH7XSmZ4Z2rLxx1SnV+opv1ynvr8Wnp/1ayZw1PsXDsh9UFRtEvZB0bKkGfnkYm2iYj14EbJctXBWyYMCGI6b7tPxzwXavPReFGMg9XonJnr4FZ+exYr+QCnjqN1DMLSjPdjtob7hYh1Ox38ad/UJELptyG33ZtAcquZBluirGn2D0xaB+ma7ZLW0Xkufe7l+CU8mFlDO36uzuTmH6Y26kt1dVKCTPrUVim12VXLgqw3++6GOT8eck/eLtWrt7b7cQmDsaq+bCA3bzA17M9rMeJ4UYyT1t4pN/5p1dWtq5hU73Dva9E53u10ln1809O/xetTyvleyHQckToz786uWevzGFzWa2wvAjeWOq80Lq7nOP8YqqIGsbMz7VnbnPPWXFwGJPyFaSq6xxY84XH+aN+Mtl7nmNf+UaH/gPb7I6vWDwnMqas3ruvxMr+QmOCYNVyTVN3mGj9KNvsFiIIbS3TnYeHiTrnq7BYnEwZ75LuQGDxSI3WP76e6BvsFhAg/0eJQbED6sQ4waLeWkZNVjUzm7UYHGHX4MGi35DNGawWFgwWCwsGCwWVgyWIAiCIAiCIAiCIAiCIAiCIAgU/gAyRDCHjvicJQAAAABJRU5ErkJggg==');`;\r\n avatarCSSClass = 'doboard_task_widget-avatar_container';\r\n initialsClass += ' doboard_task_widget-hidden_element';\r\n }\r\n if (authorDetails.taskAuthorAvatarImgSrc !== null) {\r\n avatarStyle = `background-image:url(\\'${authorDetails.taskAuthorAvatarImgSrc}\\');`;\r\n avatarCSSClass = 'doboard_task_widget-avatar_container';\r\n initialsClass = 'doboard_task_widget-hidden_element';\r\n }\r\n return {\r\n avatarStyle: avatarStyle,\r\n avatarCSSClass: avatarCSSClass,\r\n taskAuthorInitials: taskAuthorInitials,\r\n initialsClass: initialsClass\r\n }\r\n}\r\n\r\n/**\r\n * Return first found updated task ID or false if no tasks were updated\r\n * @param allTasksData\r\n * @returns {string[]|false}\r\n */\r\nfunction isAnyTaskUpdated(allTasksData) {\r\n let result = false;\r\n\r\n const updatedtasksIDS = [];\r\n\r\n for (let i = 0; i < allTasksData.length; i++) {\r\n const currentStateOfTask = allTasksData[i];\r\n const issuerId = localStorage.getItem('spotfix_user_id');\r\n if (\r\n currentStateOfTask.taskId &&\r\n currentStateOfTask.taskLastUpdate &&\r\n currentStateOfTask.taskCreatorTaskUser.toString() === issuerId.toString()\r\n ) {\r\n result = storageCheckTaskUpdate(currentStateOfTask.taskId, currentStateOfTask.taskLastUpdate);\r\n if (result) {\r\n updatedtasksIDS.push(currentStateOfTask.taskId.toString());\r\n }\r\n }\r\n }\r\n\r\n return updatedtasksIDS.length === 0 ? false : updatedtasksIDS;\r\n}\r\n\r\n/**\r\n * Check if any of the tasks has updates from site owner (not from the current user and not anonymous)\r\n * @returns {Promise}\r\n */\r\nasync function checkIfTasksHasSiteOwnerUpdates(allTasksData, params) {\r\n const updatedTaskIDs = isAnyTaskUpdated(allTasksData);\r\n let result = false;\r\n if (!updatedTaskIDs) {\r\n return false;\r\n }\r\n for (let i = 0; i < updatedTaskIDs.length; i++) {\r\n const updatedTaskId = updatedTaskIDs[i];\r\n if (typeof updatedTaskId === 'string') {\r\n const updatedTaskData = await getTasksFullDetails(params, [updatedTaskId]);\r\n if (updatedTaskData.comments) {\r\n const lastMessage = updatedTaskData.comments[0];\r\n if (\r\n lastMessage.commentUserId !== undefined &&\r\n lastMessage.commentUserId !== localStorage.getItem('spotfix_user_id') &&\r\n lastMessage.commentAuthorName !== 'Anonymous'\r\n ) {\r\n storageAddUnreadUpdateForTaskID(updatedTaskId);\r\n result = true;\r\n }\r\n }\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Check if the selection is correct - do not allow to select all page, or several different nesting nodes, or something else\r\n * @param selection\r\n * @return {boolean}\r\n */\r\nfunction isSelectionCorrect(selection) {\r\n return true;\r\n}\r\n\r\n/**\r\n * Sanitize HTML\r\n * @param {*} html\r\n * @param {*} options\r\n * @returns\r\n */\r\nfunction ksesFilter(html, options = false) {\r\n let allowedTags = {\r\n a: true,\r\n b: true,\r\n i: true,\r\n strong: true,\r\n em: true,\r\n ul: true,\r\n ol: true,\r\n li: true,\r\n p: true,\r\n s: true,\r\n br: true,\r\n span: true,\r\n blockquote: true,\r\n pre: true,\r\n div: true,\r\n img: true,\r\n input: true,\r\n label: true,\r\n textarea: true,\r\n button: true,\r\n blockquote: true,\r\n pre: true,\r\n details: true,\r\n summary: true,\r\n };\r\n let allowedAttrs = {\r\n a: ['href', 'title', 'target', 'rel', 'style', 'class'],\r\n span: ['style', 'class', 'id'],\r\n p: ['style', 'class'],\r\n div: ['style', 'class', 'id', 'data-node-path', 'data-task-id'],\r\n img: ['src', 'alt', 'title', 'class', 'style', 'width', 'height'],\r\n input: ['type', 'class', 'style', 'id', 'multiple', 'accept', 'value'],\r\n label: ['for', 'class', 'style'],\r\n textarea: ['class', 'id', 'style', 'rows', 'cols', 'readonly', 'required', 'name'],\r\n button: ['type', 'class', 'style', 'id'],\r\n details: ['class', 'style', 'open'],\r\n summary: ['class', 'style'],\r\n };\r\n\r\n if (options && options.template === 'list_issues') {\r\n allowedTags = { ...allowedTags, br: false };\r\n }\r\n\r\n const parser = new DOMParser();\r\n const doc = parser.parseFromString(html, 'text/html');\r\n function clean(node) {\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const tag = node.tagName.toLowerCase();\r\n\r\n if (options) {\r\n if (allowedTags[tag]) {\r\n // Special handling for images in 'concrete_issue_day_content' template (wrap img in link always)\r\n if (tag === 'img' && options.template === 'concrete_issue_day_content' && options.imgFilter) {\r\n const src = node.getAttribute('src') || '';\r\n const alt = node.getAttribute('alt') || '[image]';\r\n const link = doc.createElement('a');\r\n link.href = src;\r\n link.target = '_blank';\r\n link.className = 'doboard_task_widget-img-link';\r\n const img = doc.createElement('img');\r\n img.src = src;\r\n img.alt = alt;\r\n img.className = 'doboard_task_widget-comment_body-img-strict';\r\n link.appendChild(img);\r\n node.parentNode.insertBefore(link, node);\r\n node.remove();\r\n return;\r\n }\r\n }\r\n\r\n if (!allowedTags[tag]) {\r\n // Special handling for images in 'list_issues' template\r\n if (tag === 'img' && options.template === 'list_issues' && options.imgFilter) {\r\n const src = node.getAttribute('src') || '';\r\n const alt = node.getAttribute('alt') || '[image]';\r\n const link = doc.createElement('a');\r\n link.href = src;\r\n link.target = '_blank';\r\n link.textContent = alt;\r\n node.parentNode.insertBefore(link, node);\r\n }\r\n node.remove();\r\n return;\r\n }\r\n }\r\n\r\n // Remove disallowed attributes\r\n [...node.attributes].forEach(attr => {\r\n const attrName = attr.name.toLowerCase();\r\n if (!allowedAttrs[tag]?.includes(attrName) ||\r\n attrName.startsWith('on') || // Remove event handlers\r\n attr.value.toLowerCase().includes('javascript:')) {\r\n node.removeAttribute(attr.name);\r\n }\r\n });\r\n }\r\n // Recursively clean children\r\n [...node.childNodes].forEach(clean);\r\n }\r\n [...doc.body.childNodes].forEach(clean);\r\n return doc.body.innerHTML;\r\n}\r\n\nlet spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:\"\";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:\"\";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:\"\";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:\"\";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:\"wght\" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E\") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E\") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:\"\"}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:\"\";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`;\n/**\r\n * SELECTION will be grouped into three types:\r\n * 1 - Simple text within a single tag\r\n * 2 - Image tags\r\n * 3 - Any tag containing nested content\r\n * Each type will be processed differently.\r\n */\r\nconst SPOTFIX_SELECTION_TYPE_TEXT = 'text';\r\nconst SPOTFIX_SELECTION_TYPE_IMG = 'image';\r\nconst SPOTFIX_SELECTION_TYPE_ELEMENT = 'element';\r\n\r\n/**\r\n * Determines the type of selection\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {string|null} Selection type\r\n */\r\nfunction spotFixGetSelectionType(selection) {\r\n const range = selection.getRangeAt(0);\r\n const commonAncestor = range.commonAncestorContainer;\r\n\r\n // Case 1: Image selection\r\n if (spotFixGetSelectedImage(selection)) {\r\n return SPOTFIX_SELECTION_TYPE_IMG;\r\n }\r\n\r\n // Case 2: Element with nested content\r\n if (commonAncestor.nodeType === Node.ELEMENT_NODE &&\r\n commonAncestor.childNodes.length > 1 &&\r\n range.toString().trim() === '' &&\r\n range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE) {\r\n return SPOTFIX_SELECTION_TYPE_ELEMENT;\r\n }\r\n\r\n // Case 3: Simple text\r\n const hasTextContent = range.toString().trim().length > 0;\r\n const isTextNode = commonAncestor.nodeType === Node.TEXT_NODE;\r\n const isCollapsed = range.collapsed;\r\n\r\n if (hasTextContent && (isTextNode || !isCollapsed)) {\r\n return SPOTFIX_SELECTION_TYPE_TEXT;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extracts selection data from DOM Selection object\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {Object|null} Selection data with text, positions, URL and node path OR null (nothing)\r\n */\r\nfunction spotFixGetSelectedData(selection) {\r\n // Prechecks:\r\n // Selection not provided\r\n if (!selection) {spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection not provided`'); return null; }\r\n // Range not provided\r\n if (selection.rangeCount === 0) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Range not provided`'); return null; }\r\n // Several ranges provided\r\n if (selection.rangeCount > 1) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Several ranges provided`'); return null; }\r\n\r\n const range = selection.getRangeAt(0);\r\n // Selection must be within a single DOM element.\r\n if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }\r\n\r\n // FIRST - check selection type\r\n const selectionType = spotFixGetSelectionType(selection);\r\n\r\n // Selection type not determined\r\n if (!selectionType) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection type not determined`'); return null; }\r\n\r\n // SECOND - generate selectedData for each selectionType\r\n let selectedText = '';\r\n let startSelectPosition = 0;\r\n let endSelectPosition = 0;\r\n let nodePath = '';\r\n let imageUrl = '';\r\n\r\n const commonNode = range.commonAncestorContainer;\r\n\r\n switch (selectionType) {\r\n case SPOTFIX_SELECTION_TYPE_TEXT:\r\n if (range.toString().trim().length === 0) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection text is empty`');\r\n return null;\r\n }\r\n const commonNodeElement = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n selectedText = range.toString();\r\n startSelectPosition = range.startOffset;\r\n endSelectPosition = range.endOffset;\r\n if ( startSelectPosition === 0 && selectedText.length > endSelectPosition ) {\r\n endSelectPosition = selectedText.length;\r\n }\r\n nodePath = spotFixCalculateNodePath(commonNodeElement);\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_IMG:\r\n const imgElement = range.startContainer;\r\n const selectedImage = spotFixGetSelectedImage(selection);\r\n selectedText = `Image (${selectedImage.alt ? selectedImage.alt : 'no description'})`;\r\n nodePath = spotFixCalculateNodePath(selectedImage);\r\n // For images, positions represent the image element position in parent\r\n startSelectPosition = Array.from(imgElement.parentNode.children).indexOf(imgElement);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_ELEMENT:\r\n const element = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n if (element.childNodes.length <= 1) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection have not inner data`');\r\n return null;\r\n }\r\n selectedText = element.textContent || '';\r\n nodePath = spotFixCalculateNodePath(element);\r\n // For elements, positions represent the element's position in parent\r\n startSelectPosition = Array.from(element.parentNode.children).indexOf(element);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n }\r\n\r\n // Get page URL\r\n const pageURL = window.location.href;\r\n\r\n return {\r\n startSelectPosition,\r\n endSelectPosition,\r\n selectedText: selectedText.trim(),\r\n pageURL,\r\n nodePath,\r\n selectionType,\r\n imageUrl: selectionType === SPOTFIX_SELECTION_TYPE_IMG ? imageUrl : ''\r\n };\r\n}\r\n\r\n/**\r\n * Highlight elements.\r\n * @param {[object]} spotsToBeHighlighted\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightElements(spotsToBeHighlighted, widgetInstance) {\r\n\r\n if (spotsToBeHighlighted.length === 0) return;\r\n\r\n const elementsMap = new Map();\r\n\r\n // Grouping elements with validation\r\n spotsToBeHighlighted.forEach(spot => {\r\n // nodePath validating: is array\r\n if (!spot?.nodePath || !Array.isArray(spot?.nodePath)) {\r\n spotFixDebugLog('Invalid spot: missing or invalid nodePath: ' + spot);\r\n return;\r\n }\r\n\r\n // nodePath validating: is valid indexes list\r\n if (!this.spotFixIsValidNodePath(spot.nodePath)) {\r\n spotFixDebugLog('Invalid nodePath format: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n const element = spotFixRetrieveNodeFromPath(spot.nodePath);\r\n if (!element) {\r\n spotFixDebugLog('Element not found for path: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n if ( ! spot.selectionType ) {\r\n // @ToDo need to apply backward capability here\r\n // just `spot.selectionType = 'text';` is not able, this opens ability to unauthorized modify website content\r\n spotFixDebugLog('Selection type is not provided.');\r\n return;\r\n }\r\n\r\n // selectionType parameter validating\r\n if (\r\n spot.selectionType &&\r\n ![\r\n SPOTFIX_SELECTION_TYPE_TEXT,\r\n SPOTFIX_SELECTION_TYPE_IMG,\r\n SPOTFIX_SELECTION_TYPE_ELEMENT\r\n ].includes(spot.selectionType)\r\n ) {\r\n spotFixDebugLog('Invalid selection type: ' + spot.selectionType);\r\n return;\r\n }\r\n\r\n if (!elementsMap.has(element)) {\r\n elementsMap.set(element, []);\r\n }\r\n elementsMap.get(element).push(spot);\r\n });\r\n\r\n elementsMap.forEach((spots, element) => {\r\n const selectionType = spots[0].selectionType;\r\n\r\n // MAIN LOGIC: highlight for the different types\r\n switch (selectionType) {\r\n case 'image':\r\n this.spotFixHighlightImageElement(element);\r\n break;\r\n\r\n case 'element':\r\n this.spotFixHighlightNestedElement(element);\r\n break;\r\n\r\n case 'text':\r\n this.spotFixHighlightTextInElement(element, spots, widgetInstance);\r\n break;\r\n\r\n default:\r\n spotFixDebugLog('Unknown selection type: ' + selectionType);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Highlight image element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightImageElement(element) {\r\n if (element.tagName !== 'IMG') {\r\n spotFixDebugLog('Expected IMG element for image highlight, got: ' + element.tagName);\r\n return;\r\n }\r\n element.classList.add('doboard_task_widget-image_selection');\r\n}\r\n\r\n/**\r\n * Highlight nested element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightNestedElement(element) {\r\n element.classList.add('doboard_task_widget-element_selection');\r\n}\r\n\r\n/**\r\n * Highlight text in element with span wrapping\r\n * @param {Element} element\r\n * @param {Array} spots\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightTextInElement(element, spots,widgetInstance) {\r\n let tooltipTitleText = '';\r\n if (spots[0].isFixed) {\r\n tooltipTitleText = `This issue already fixed.`;\r\n } else {\r\n tooltipTitleText = `We are already working on this issue.`;\r\n }\r\n\r\n const tooltip = `
\r\n \r\n \r\n
${tooltipTitleText}
\r\n
You can see history Here
\r\n
\r\n
`;\r\n\r\n const spotfixHighlightOpen = `${tooltip}`;\r\n const spotfixHighlightClose = ``;\r\n\r\n let text = element.textContent;\r\n const spotSelectedText = spots[0].selectedText;\r\n\r\n // meta.selectedText can not be empty string\r\n if ( ! spotSelectedText ) {\r\n spotFixDebugLog('Provided metadata is invalid.');\r\n return;\r\n }\r\n\r\n const markers = [];\r\n\r\n // Mark positions for inserting\r\n spots.forEach(spot => {\r\n // Validating positions\r\n const startPos = parseInt(spot.startSelectPosition) || 0;\r\n const endPos = parseInt(spot.endSelectPosition) || 0;\r\n\r\n if (startPos < 0 || endPos > text.length || startPos > endPos) {\r\n spotFixDebugLog('Invalid text positions: ' + spot);\r\n return;\r\n }\r\n\r\n markers.push({ position: startPos, type: 'start' });\r\n markers.push({ position: endPos, type: 'end' });\r\n });\r\n\r\n if (markers.length === 0) return;\r\n\r\n // Sort markers backward\r\n markers.sort((a, b) => b.position - a.position);\r\n\r\n // Check here that element (from meta.nodePath) contains same inner text as in meta.selectedText\r\n // Is the `text` in the element equal to the selected text `spotSelectedText`\r\n if ( text.slice(markers[1].position, markers[0].position) !== spotSelectedText ) {\r\n spotFixDebugLog('It is not allow to highlight element by provided metadata.');\r\n return;\r\n }\r\n\r\n let result = text;\r\n markers.forEach(marker => {\r\n const insertText = marker.type === 'start'\r\n ? spotfixHighlightOpen\r\n : spotfixHighlightClose;\r\n\r\n result = result.slice(0, marker.position) + insertText + result.slice(marker.position);\r\n });\r\n\r\n // Safety HTML insert\r\n try {\r\n element.innerHTML = ksesFilter(result);\r\n document.querySelectorAll('.doboard_task_widget-see-task').forEach(link => {\r\n link.addEventListener('click', (e) => {\r\n\r\n e.preventDefault();\r\n const classList = link.className.split(' ');\r\n const idClass = classList.find(cls => cls.includes('__task-id-'));\r\n let taskId = null;\r\n if (idClass) {\r\n taskId = idClass.split('__task-id-')[1];\r\n }\r\n if (taskId) {\r\n widgetInstance.currentActiveTaskId = taskId;\r\n widgetInstance.showOneTask();\r\n }\r\n });\r\n });\r\n } catch (error) {\r\n spotFixDebugLog('Error updating element content: ' + error);\r\n }\r\n}\r\n\r\n/**\r\n * Scroll to an element by tag, class, and text content\r\n * @param {array} path - The path to the element\r\n * @return {boolean} - True if the element was found and scrolled to, false otherwise\r\n */\r\nfunction spotFixScrollToNodePath(path) {\r\n const node = spotFixRetrieveNodeFromPath(path);\r\n if (node && node.scrollIntoView) {\r\n node.scrollIntoView({ behavior: 'smooth', block: 'center' });\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction spotFixRemoveHighlights() {\r\n const textSelectionclassName = 'doboard_task_widget-text_selection';\r\n const spans = document.querySelectorAll('.' + textSelectionclassName);\r\n const affectedParents = new Set(); // Track unique parents\r\n\r\n spans.forEach(span => {\r\n const parent = span.parentNode;\r\n affectedParents.add(parent); // Mark parent as affected\r\n const tooltip = span.querySelector('.doboard_task_widget-text_selection_tooltip');\r\n if (tooltip) tooltip.remove();\r\n\r\n // Move all child nodes out of the span and into the parent\r\n while (span.firstChild) {\r\n parent.insertBefore(span.firstChild, span);\r\n }\r\n parent.removeChild(span);\r\n });\r\n\r\n // Normalize all affected parents to merge adjacent text nodes\r\n affectedParents.forEach(parent => parent.normalize());\r\n\r\n const elementSelectionClassName = 'doboard_task_widget-element_selection';\r\n const elements = document.querySelectorAll(`.${elementSelectionClassName}`);\r\n elements.forEach(element => {\r\n element.classList.remove(elementSelectionClassName);\r\n });\r\n const imageSelectionClassName = 'doboard_task_widget-image_selection';\r\n const images = document.querySelectorAll(`.${imageSelectionClassName}`);\r\n images.forEach(element => {\r\n element.classList.remove(imageSelectionClassName);\r\n });\r\n}\r\n\r\n/**\r\n * Validate nodePath as array of indices\r\n * @param {Array} nodePath\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsValidNodePath(nodePath) {\r\n if (!Array.isArray(nodePath)) return false;\r\n if (nodePath.length === 0) return false;\r\n\r\n return nodePath.every(index => {\r\n return Number.isInteger(index) && index >= 0 && index < 1000;\r\n });\r\n}\r\n\r\n/**\r\n * Try to find selected image in selection.\r\n * @param selection\r\n * @returns {Node|*|null}\r\n */\r\nfunction spotFixGetSelectedImage(selection) {\r\n\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\r\n return null;\r\n }\r\n\r\n const range = selection.getRangeAt(0);\r\n\r\n // Is current end container IMG\r\n if (range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE &&\r\n range.startContainer.tagName === 'IMG') {\r\n return range.startContainer;\r\n }\r\n\r\n // Get img in the range\r\n const walker = document.createTreeWalker(\r\n range.commonAncestorContainer,\r\n NodeFilter.SHOW_ELEMENT,\r\n {\r\n acceptNode: function(node) {\r\n return node.tagName === 'IMG' &&\r\n spotFixIsElementInRange(node, range) ?\r\n NodeFilter.FILTER_ACCEPT :\r\n NodeFilter.FILTER_REJECT;\r\n }\r\n }\r\n );\r\n\r\n let imgNode = walker.nextNode();\r\n if (imgNode) {\r\n return imgNode;\r\n }\r\n\r\n // start/end containers\r\n const startElement = spotFixGetElementFromNode(range.startContainer);\r\n const endElement = spotFixGetElementFromNode(range.endContainer);\r\n\r\n // If selection starts on image\r\n if (startElement && startElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(startElement, range)) {\r\n return startElement;\r\n }\r\n\r\n if (endElement && endElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(endElement, range)) {\r\n return endElement;\r\n }\r\n\r\n // 4. Get closest IMG\r\n const nearbyElements = spotFixFindNearbyElements(range);\r\n for (const element of nearbyElements) {\r\n if (element.tagName === 'IMG') {\r\n return element;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction spotFixIsElementInRange(element, range) {\r\n const elementRange = document.createRange();\r\n elementRange.selectNode(element);\r\n return range.compareBoundaryPoints(Range.START_TO_START, elementRange) <= 0 &&\r\n range.compareBoundaryPoints(Range.END_TO_END, elementRange) >= 0;\r\n}\r\n\r\nfunction spotFixIsElementPartiallySelected(element, range) {\r\n const elementRect = element.getBoundingClientRect();\r\n const rangeRect = range.getBoundingClientRect();\r\n\r\n // bounding rectangles is crossed\r\n return !(elementRect.right < rangeRect.left ||\r\n elementRect.left > rangeRect.right ||\r\n elementRect.bottom < rangeRect.top ||\r\n elementRect.top > rangeRect.bottom);\r\n}\r\n\r\nfunction spotFixGetElementFromNode(node) {\r\n return node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n}\r\n\r\n/**\r\n * Find nearby elements in the range.\r\n * @param range\r\n * @returns {*[]}\r\n */\r\nfunction spotFixFindNearbyElements(range) {\r\n const elements = [];\r\n const container = range.commonAncestorContainer;\r\n\r\n // search elements\r\n const previousElement = container.previousElementSibling;\r\n const nextElement = container.nextElementSibling;\r\n\r\n if (previousElement) {\r\n elements.push(previousElement);\r\n }\r\n if (nextElement) {\r\n elements.push(nextElement);\r\n }\r\n\r\n // Also check child container\r\n if (container.nodeType === Node.ELEMENT_NODE) {\r\n const children = container.children;\r\n for (let i = 0; i < children.length; i++) {\r\n if (spotFixIsElementPartiallySelected(children[i], range)) {\r\n elements.push(children[i]);\r\n }\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Calculate the path of a DOM node\r\n *\r\n * @param {Node} node\r\n * @return {int[]}\r\n */\r\nfunction spotFixCalculateNodePath(node) {\r\n let path = [];\r\n while (node) {\r\n let index = 0;\r\n let sibling = node.previousSibling;\r\n while (sibling) {\r\n if (sibling.nodeType === 1) {\r\n index++;\r\n }\r\n sibling = sibling.previousSibling;\r\n }\r\n path.unshift(index);\r\n node = node.parentNode;\r\n }\r\n\r\n // Hard fix - need to remove first element to work correctly\r\n path.shift();\r\n\r\n return path;\r\n}\r\n\r\n/**\r\n * Retrieve a DOM node from a path\r\n *\r\n * @param {int[]} path\r\n * @return {*|null}\r\n */\r\nfunction spotFixRetrieveNodeFromPath(path) {\r\n // @ToDo check if the path is correct\r\n if ( ! path ) {\r\n return null;\r\n }\r\n\r\n let node = document;\r\n for (let i = 0; i < path.length; i++) {\r\n node = node.children[path[i]];\r\n if ( ! node ) {\r\n return null;\r\n }\r\n }\r\n return node;\r\n}\r\n\n/**\r\n * Return bool if widget is closed in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetWidgetIsClosed() {\r\n return localStorage.getItem('spotfix_widget_is_closed') === '1';\r\n}\r\n\r\n/**\r\n * Return bool if widget closed state is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageWidgetCloseIsSet() {\r\n return localStorage.getItem('spotfix_widget_is_closed') !== null;\r\n}\r\n\r\n/**\r\n * Save widget closed state\r\n * @param visible\r\n */\r\nfunction storageSetWidgetIsClosed(visible) {\r\n localStorage.setItem('spotfix_widget_is_closed', visible ? '1' : '0');\r\n}\r\n\r\n/**\r\n * Return bool if user is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetUserIsDefined() {\r\n return localStorage.getItem('spotfix_user_id') !== null;\r\n}\r\n\r\n/**\r\n * Save data for updates check\r\n * @param tasks\r\n */\r\nfunction storageSaveTasksUpdateData(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n\r\n tasks.forEach(task => {\r\n if (task.taskId && task.taskLastUpdate) {\r\n storedTasks[task.taskId] = {\r\n taskId: task.taskId,\r\n taskLastUpdate: task.taskLastUpdate\r\n };\r\n }\r\n });\r\n\r\n localStorage.setItem('spotfix_task_updates', JSON.stringify(storedTasks));\r\n}\r\n\r\nfunction storageSaveTasksCount(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n const count = tasks.filter(task => {\r\n return task.taskMeta;\r\n })?.length;\r\n\r\n localStorage.setItem('spotfix_tasks_count', `${count}`);\r\n}\r\n\r\n/**\r\n * Check if a specific task has been updated since last check\r\n * @param taskId\r\n * @param currentLastUpdate\r\n * @returns {boolean|null}\r\n */\r\nfunction storageCheckTaskUpdate(taskId, currentLastUpdate) {\r\n if (!taskId || !currentLastUpdate) {\r\n return null;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n const storedTask = storedTasks[taskId];\r\n\r\n if (!storedTask) {\r\n return false;\r\n }\r\n\r\n const storedUpdate = new Date(storedTask.taskLastUpdate);\r\n const currentUpdate = new Date(currentLastUpdate);\r\n return currentUpdate > storedUpdate;\r\n}\r\n\r\n/**\r\n * Add unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageAddUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n if (!storedUnread.includes(taskId)) {\r\n storedUnread.push(taskId);\r\n }\r\n\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Remove unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageRemoveUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n storedUnread = storedUnread.filter(id => id !== taskId);\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Check if there are any unread updates\r\n * @returns {boolean}\r\n */\r\nfunction storageTasksHasUnreadUpdates() {\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.length > 0;\r\n}\r\n\r\n/**\r\n * Check if a specific task has unread updates\r\n * @param taskId\r\n * @returns {boolean}\r\n */\r\nfunction storageProvidedTaskHasUnreadUpdates(taskId) {\r\n if (!taskId) {\r\n return false;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.includes(taskId.toString());\r\n}\r\n\r\nfunction storageSaveSpotfixVersion (version) {\r\n localStorage.setItem('spotfix_app_version', `${version}`);\r\n}\r\n\r\nfunction clearLocalstorageOnLogout () {\r\n localStorage.removeItem('spotfix_email');\r\n localStorage.removeItem('spotfix_session_id');\r\n localStorage.removeItem('spotfix_user_id');\r\n localStorage.setItem('spotfix_widget_is_closed', '1');\r\n}\r\n\n/**\r\n * File uploader handler for managing file attachments with validation and upload capabilities\r\n */\r\nclass FileUploader {\r\n /**\r\n * Create a new FileUploader instance\r\n * @param {function} escapeHtmlHandler - Function to escape HTML strings for security\r\n */\r\n constructor(escapeHtmlHandler) {\r\n /** @type {Array<{id: string, file: File}>} */\r\n this.files = [];\r\n\r\n /** @type {number} Maximum allowed file size in bytes */\r\n this.maxFileSize = 5 * 1024 * 1024; // 5MB\r\n\r\n /** @type {number} Maximum total size for all files in bytes */\r\n this.maxTotalSize = 25 * 1024 * 1024; // 25MB\r\n\r\n /** @type {number} Maximum number of files allowed */\r\n this.maxFiles = 5;\r\n\r\n /** @type {string[]} Allowed MIME types for files */\r\n this.allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'text/plain', 'application/msword'];\r\n\r\n /** @type {function} HTML escaping function for XSS protection */\r\n this.escapeHtmlHandler = escapeHtmlHandler;\r\n\r\n /** @type {string[]} File size units for display */\r\n this.SIZE_UNITS = ['Bytes', 'KB', 'MB', 'GB'];\r\n }\r\n\r\n /**\r\n * Initialize elements and bindings. Should be called only for comments.\r\n * @returns {void}\r\n */\r\n init() {\r\n this.initializeElements();\r\n this.bindFilesInputChange();\r\n }\r\n\r\n /**\r\n * Define widget elements to work with uploader.\r\n * @returns {void}\r\n */\r\n initializeElements() {\r\n /** @type {HTMLInputElement|null} */\r\n this.fileInput = document.getElementById('doboard_task_widget__file-upload__file-input-button');\r\n\r\n /** @type {HTMLElement|null} */\r\n this.fileList = document.getElementById('doboard_task_widget__file-upload__file-list');\r\n\r\n this.uploaderWrapper = document.getElementById('doboard_task_widget__file-upload__wrapper');\r\n\r\n /** @type {HTMLElement|null} */\r\n this.errorMessage = document.getElementById('doboard_task_widget__file-upload__error');\r\n\r\n if (!this.fileInput || !this.fileList || !this.errorMessage || this.uploaderWrapper) {\r\n console.warn('File uploader elements not found');\r\n }\r\n }\r\n\r\n /**\r\n * Define hidden file input change to run uploader logic.\r\n * @returns {void}\r\n */\r\n bindFilesInputChange() {\r\n if (this.fileInput) {\r\n this.fileInput.addEventListener('change', (e) => this.handleFileInputChange(e));\r\n }\r\n }\r\n\r\n /**\r\n * Bind action to paperclip button.\r\n * @param {HTMLElement} element - The paperclip button element\r\n * @returns {void}\r\n */\r\n bindPaperClipAction(element) {\r\n element.addEventListener('click', (e) => {\r\n e.preventDefault();\r\n if (this.fileInput) {\r\n this.fileInput.click();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Handle file input change event\r\n * @param {Event} event - File input change event\r\n * @returns {void}\r\n */\r\n handleFileInputChange(event) {\r\n this.clearError();\r\n\r\n const selectedFiles = Array.from(event.target.files);\r\n if (this.files.length + selectedFiles.length > this.maxFiles) {\r\n this.showError(`Maximum ${this.maxFiles} files can be attached.`);\r\n return;\r\n }\r\n const validFiles = selectedFiles.filter(file => this.validateFile(file));\r\n\r\n validFiles.forEach(file => this.addFile(file));\r\n\r\n // Reset input to allow selecting same files again\r\n event.target.value = '';\r\n\r\n // show wrapper\r\n this.uploaderWrapper.style.display = 'block';\r\n }\r\n\r\n /**\r\n * Validate a file against upload constraints\r\n * @param {File} file - File to validate\r\n * @returns {boolean} True if file is valid, false otherwise\r\n */\r\n validateFile(file) {\r\n // Check file size\r\n if (file.size > this.maxFileSize) {\r\n this.showError(`File \"${file.name}\" is too large. Maximum size: ${this.formatFileSize(this.maxFileSize)}`);\r\n return false;\r\n }\r\n\r\n // Check total size\r\n const totalSize = this.getTotalSize() + file.size;\r\n if (totalSize > this.maxTotalSize) {\r\n this.showError(`Total files size exceeded. Maximum: ${this.formatFileSize(this.maxTotalSize)}`);\r\n return false;\r\n }\r\n\r\n // Check file type\r\n if (this.allowedTypes.length > 0 && !this.allowedTypes.includes(file.type)) {\r\n this.showError(`File type \"${file.type}\" for \"${file.name}\" is not supported.`);\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Calculate total size of all files\r\n * @returns {number} Total size in bytes\r\n */\r\n getTotalSize() {\r\n return this.files.reduce((sum, fileData) => sum + fileData.file.size, 0);\r\n }\r\n\r\n /**\r\n * Add a file to the upload queue\r\n * @param {File} file - File to add\r\n * @returns {void}\r\n */\r\n addFile(file) {\r\n const fileWithId = {\r\n id: this.generateFileId(),\r\n file: file\r\n };\r\n\r\n this.files.push(fileWithId);\r\n this.renderFileList();\r\n }\r\n\r\n /**\r\n * Generate a unique file ID\r\n * @returns {string} Unique file identifier\r\n * @private\r\n */\r\n generateFileId() {\r\n return Date.now() + Math.random().toString(36).substr(2, 9);\r\n }\r\n\r\n /**\r\n * Remove a file from the upload queue\r\n * @param {string} fileId - ID of the file to remove\r\n * @returns {void}\r\n */\r\n removeFile(fileId) {\r\n this.files = this.files.filter(f => f.id !== fileId);\r\n this.renderFileList();\r\n this.clearError();\r\n }\r\n\r\n /**\r\n * Render the file list in the UI\r\n * @returns {void}\r\n */\r\n renderFileList() {\r\n if (!this.fileList) return;\r\n\r\n if (this.files.length === 0) {\r\n this.fileList.innerHTML = ksesFilter('
No files attached
');\r\n return;\r\n }\r\n\r\n const fileItems = this.files.map(fileData => this.createFileItem(fileData));\r\n this.fileList.innerHTML = ksesFilter('');\r\n fileItems.forEach(item => this.fileList.appendChild(item));\r\n }\r\n\r\n /**\r\n * Create file item element for display\r\n * @param {object} fileData - File data object\r\n * @param {string} fileData.id - File identifier\r\n * @param {File} fileData.file - File object\r\n * @returns {HTMLDivElement} File item DOM element\r\n */\r\n createFileItem(fileData) {\r\n const { file, id } = fileData;\r\n const fileItem = document.createElement('div');\r\n fileItem.className = 'doboard_task_widget__file-upload__file-item';\r\n\r\n fileItem.innerHTML = ksesFilter(`\r\n
\r\n
\r\n
${this.escapeHtmlHandler(String(file.name))}
\r\n
${this.formatFileSize(file.size)}
\r\n
\r\n
\r\n \r\n `);\r\n\r\n const removeBtn = fileItem.querySelector('.doboard_task_widget__file-upload__remove-btn');\r\n removeBtn.addEventListener('click', () => this.removeFile(id));\r\n\r\n return fileItem;\r\n }\r\n\r\n /**\r\n * Format file size for display\r\n * @param {number} bytes - File size in bytes\r\n * @returns {string} Formatted file size string\r\n */\r\n formatFileSize(bytes) {\r\n if (bytes === 0) return '0 Bytes';\r\n\r\n const k = 1024;\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n\r\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + this.SIZE_UNITS[i];\r\n }\r\n\r\n /**\r\n * Show uploader error message\r\n * @param {string} message - Error message to display\r\n * @returns {void}\r\n */\r\n showError(message) {\r\n if (this.errorMessage) {\r\n this.errorMessage.textContent = message;\r\n this.errorMessage.style.display = 'block';\r\n }\r\n }\r\n\r\n /**\r\n * Clear uploader error message\r\n * @returns {void}\r\n */\r\n clearError() {\r\n if (this.errorMessage) {\r\n this.errorMessage.textContent = '';\r\n this.errorMessage.style.display = 'none';\r\n }\r\n }\r\n\r\n /**\r\n * Check if there are files to send\r\n * @returns {boolean} True if files are present, false otherwise\r\n */\r\n hasFiles() {\r\n return this.files.length > 0;\r\n }\r\n\r\n /**\r\n * Clear all files from upload queue\r\n * @returns {void}\r\n */\r\n clearFiles() {\r\n this.files = [];\r\n this.renderFileList();\r\n }\r\n\r\n /**\r\n * Validate file data structure before upload\r\n * @param {object} fileData - File data object to validate\r\n * @param {string} fileData.sessionId - Session identifier\r\n * @param {object} fileData.params - Additional parameters\r\n * @param {string} fileData.params.accountId - Account identifier\r\n * @param {string} fileData.params.projectToken - Project token\r\n * @param {string} fileData.commentId - Comment identifier\r\n * @param {string} fileData.fileName - File name\r\n * @param {File} fileData.fileBinary - File binary data\r\n * @returns {object} Validated file data\r\n * @throws {Error} When file data validation fails\r\n */\r\n validateFileData(fileData) {\r\n const validations = [\r\n { field: 'sessionId', type: 'string', message: 'No valid session found.' },\r\n { field: 'params.accountId', type: 'string', message: 'No valid account ID found.' },\r\n { field: 'params.projectToken', type: 'string', message: 'No valid project token found.' },\r\n { field: 'commentId', type: 'string', message: 'No valid commentId found.' },\r\n { field: 'fileName', type: 'string', message: 'No valid filename found.' }\r\n ];\r\n\r\n for (const validation of validations) {\r\n const value = this.getNestedValue(fileData, validation.field);\r\n if (!value || typeof value !== validation.type) {\r\n throw new Error(validation.message);\r\n }\r\n }\r\n\r\n if (!fileData.fileBinary || !(fileData.fileBinary instanceof File)) {\r\n throw new Error('No valid file object found.');\r\n }\r\n\r\n return fileData;\r\n }\r\n\r\n /**\r\n * Helper to get nested object values\r\n * @param {object} obj - Object to traverse\r\n * @param {string} path - Dot notation path to value\r\n * @returns {*} Value at the specified path\r\n * @private\r\n */\r\n getNestedValue(obj, path) {\r\n return path.split('.').reduce((current, key) => current?.[key], obj);\r\n }\r\n\r\n /**\r\n * Send single file attachment\r\n * @param {object} fileData - File data for upload\r\n * @returns {Promise} Upload response\r\n */\r\n async sendSingleAttachment(fileData) {\r\n const validatedFileData = await this.validateFileData(fileData);\r\n return await attachmentAddDoboard(validatedFileData);\r\n }\r\n\r\n /**\r\n * Send all attachments for a comment\r\n * @param {object} params - Upload parameters\r\n * @param {string} sessionId - Session identifier\r\n * @param {string} commentId - Comment identifier\r\n * @returns {Promise} Upload results\r\n */\r\n async sendAttachmentsForComment(params, sessionId, commentId) {\r\n /** @type {object} */\r\n const results = {\r\n preparedFilesCount: this.files.length,\r\n sentFilesCount: 0,\r\n fileResults: [],\r\n success: true\r\n };\r\n\r\n for (let i = 0; i < this.files.length; i++) {\r\n const fileData = this.files[i];\r\n /** @type {object} */\r\n const result = {\r\n success: false,\r\n response: null,\r\n error: null\r\n };\r\n\r\n try {\r\n const attachmentData = {\r\n params,\r\n sessionId,\r\n commentId,\r\n fileName: fileData.file.name,\r\n fileBinary: fileData.file,\r\n attachmentOrder: i\r\n };\r\n\r\n const response = await this.sendSingleAttachment(attachmentData);\r\n result.response = response;\r\n result.success = response.status === 200;\r\n\r\n if (result.success) {\r\n results.sentFilesCount++;\r\n }\r\n } catch (error) {\r\n result.error = error.message;\r\n }\r\n\r\n results.fileResults.push(result);\r\n }\r\n\r\n results.success = results.preparedFilesCount === results.sentFilesCount;\r\n this.clearFiles();\r\n\r\n return results;\r\n }\r\n}\r\n\nclass SpotFixTemplatesLoader {\r\n static getTemplateCode(templateName) {\r\n const templateMethod = this[templateName];\r\n\r\n if (typeof templateMethod !== 'function') {\r\n throw new Error(`Template method '${templateName}' not found`);\r\n }\r\n\r\n let template = templateMethod.call(this).trim();\r\n\r\n return template;\r\n }\r\n\r\n static all_issues() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n All spots \r\n
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n
`;\r\n }\r\n\r\n static concrete_issue() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n All {{issuesCounter}}\r\n
\r\n
{{issueTitle}}
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n \r\n \r\n
\r\n
\r\n
Attached files
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static concrete_issue_day_content() {\r\n return `\r\n
\r\n
{{dayContentMonthDay}}
\r\n
{{dayContentMessages}}
\r\n {{statusFixedHtml}}\r\n
\r\n`;\r\n }\r\n\r\n static concrete_issue_messages() {\r\n return `\r\n
\r\n
\r\n {{taskAuthorInitials}}\r\n
\r\n
\r\n
{{commentBody}}
\r\n
{{commentTime}}
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static create_issue() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n Report an issue\r\n
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n Tell us about any issue you’re experiencing on {{currentDomain}}. \r\n You’re also welcome to review spelling, grammar, or ask a question related to this page.\r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n\r\n If you want to receive notifications by email write here you email contacts.\r\n\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n Note about DoBoard register and accepting email notifications about tasks have to be here.\r\n\r\n
\r\n\r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static list_issues() {\r\n return `\r\n
\r\n
\r\n {{taskAuthorInitials}}\r\n
\r\n
\r\n
\r\n
\r\n {{taskTitle}}\r\n
\r\n \"\"\r\n
\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n {{statusFixedHtml}}\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static user_menu() {\r\n return `\r\n
\r\n
\r\n
\r\n
\r\n \"\"\r\n Back\r\n
\r\n
\r\n \"\"\r\n
\r\n
\r\n
\r\n \"\"\r\n {{userName}}\r\n {{email}}\r\n \r\n Sign up or Log in\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \"\"\r\n
\r\n \r\n \r\n Show widget on my screen\r\n \r\n The widget will be visible again if you select any text on the site\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n \"\"\r\n Log out\r\n \r\n
\r\n
\r\n
\r\n
\r\n {{spotfixVersion}}\r\n Powered by\r\n \r\n doBoard\r\n \r\n
\r\n
\r\n
`;\r\n }\r\n\r\n static wrap() {\r\n return `\r\n
\r\n\r\n\r\n
\r\n
`;\r\n }\r\n\r\n static wrap_review() {\r\n return `\r\n`;\r\n }\r\n\r\n static fixedHtml() {\r\n return `

Finished

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

This issue already fixed

`;\r\n }\r\n\r\n}\r\n\nclass SpotFixSVGLoader {\r\n static loadSVG(svgName) {\r\n const svgMethod = this[svgName];\r\n\r\n if (typeof svgMethod !== 'function') {\r\n throw new Error(`Template method '${svgName}' not found`);\r\n }\r\n\r\n return svgMethod.call(this).trim();\r\n }\r\n\r\n static getAsRawSVG(svgName) {\r\n return this.loadSVG(svgName);\r\n }\r\n\r\n static getAsDataURI(svgName) {\r\n const svg = this.loadSVG(svgName);\r\n return this.svgToDataURI(svg);\r\n }\r\n\r\n static svgToDataURI(svgString) {\r\n const bytes = new TextEncoder().encode(svgString);\r\n const baseBtoa = btoa(String.fromCharCode(...bytes));\r\n return `data:image/svg+xml;base64,${baseBtoa}`;\r\n }\r\n\r\n static chevronBack() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static chevronBackDark() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static buttonCloseScreen() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static buttonSendMessage() {\r\n return `\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n`;\r\n }\r\n\r\n static buttonPaperClip() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static logoDoBoardGreen() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static logoDoBoardWrap() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotPublic() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotPrivate() {\r\n return `\r\n\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotWidgetWrapPencil() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconLinkChain() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconEllipsesMore() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconAvatar() {\r\n return `\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n`;\r\n }\r\n\r\n static iconEye() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconDoor() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconPlus() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconMaximize() {\r\n return `\r\n\r\n\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconMarker() {\r\n return ``;\r\n }\r\n}\r\n\nclass SpotFixSourcesLoader {\r\n\r\n constructor() {\r\n this.loadAll();\r\n }\r\n\r\n getCSSCode() {\r\n // global gulp wrapper var\r\n return spotFixCSS;\r\n }\r\n\r\n loadAll() {\r\n this.loadFonts();\r\n this.loadCSS();\r\n };\r\n\r\n loadFonts() {\r\n const preconnect_first = document.createElement('link');\r\n preconnect_first.rel = 'preconnect';\r\n preconnect_first.href = 'https://fonts.googleapis.com';\r\n document.head.appendChild(preconnect_first);\r\n\r\n const preconnect_second = document.createElement('link');\r\n preconnect_second.rel = 'preconnect';\r\n preconnect_second.href = 'https://fonts.gstatic.com';\r\n preconnect_second.crossOrigin = 'crossorigin';\r\n document.head.appendChild(preconnect_second);\r\n\r\n const fontLink = document.createElement('link');\r\n fontLink.rel = 'stylesheet';\r\n fontLink.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap';\r\n document.head.appendChild(fontLink);\r\n }\r\n\r\n loadCSS() {\r\n const style = document.createElement('style');\r\n style.setAttribute('id', 'spotfix_css');\r\n style.textContent = this.getCSSCode();\r\n document.head.appendChild(style);\r\n }\r\n}\r\n\ndocument.dispatchEvent(new CustomEvent('spotFixLoaded', {\r\n detail: {\r\n timestamp: new Date().toISOString(),\r\n message: 'All scripts loaded successfully'\r\n }\r\n}));\r\n"],"names":["DOBOARD_API_URL","spotfixApiCall","async","data","method","accountId","undefined","Error","key","formData","FormData","hasOwnProperty","append","let","endpointUrl","URL","error","response","await","fetch","body","networkError","message","responseBody","json","parseError","operation_status","errorMessage","operation_message","userConfirmEmailDoboard","emailConfirmationToken","email_confirmation_token","encodeURIComponent","result","sessionId","session_id","userId","user_id","email","accounts","operationStatus","createTaskDoboard","taskDetails","project_token","projectToken","project_id","projectId","localStorage","getItem","name","taskTitle","comment","taskDescription","meta","taskMeta","task_type","taskId","task_id","createTaskCommentDoboard","status","commentId","comment_id","attachmentAddDoboard","fileData","params","account_id","filename","fileName","file","fileBinary","attachment_order","attachmentOrder","registerUserDoboard","nickname","pageURL","confirmation_url","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","spotFixCSS","SPOTFIX_SELECTION_TYPE_TEXT","SPOTFIX_SELECTION_TYPE_IMG","SPOTFIX_SELECTION_TYPE_ELEMENT","spotFixGetSelectionType","range","getRangeAt","commonAncestor","commonAncestorContainer","spotFixGetSelectedImage","startContainer","endContainer","hasTextContent","isTextNode","TEXT_NODE","isCollapsed","collapsed","rangeCount","selectionType","startSelectPosition","endSelectPosition","commonNode","commonNodeElement","startOffset","endOffset","spotFixCalculateNodePath","imgElement","selectedImage","from","children","indexOf","imageUrl","widgetInstance","elementsMap","Map","spot","spotFixIsValidNodePath","spotFixRetrieveNodeFromPath","has","set","spots","spotFixHighlightImageElement","spotFixHighlightNestedElement","spotFixHighlightTextInElement","tooltipTitleText","spotfixHighlightOpen","text","spotSelectedText","markers","startPos","parseInt","endPos","slice","marker","insertText","idClass","cls","path","scrollIntoView","block","spans","affectedParents","Set","elementSelectionClassName","parent","tooltip","firstChild","removeChild","normalize","imageSelectionClassName","every","index","isInteger","imgNode","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","spotFixIsElementInRange","FILTER_ACCEPT","FILTER_REJECT","nextNode","startElement","spotFixGetElementFromNode","endElement","spotFixIsElementPartiallySelected","spotFixFindNearbyElements","elementRange","createRange","selectNode","compareBoundaryPoints","Range","START_TO_START","END_TO_END","elementRect","rangeRect","right","left","elements","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","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/SpotFixSVGLoader.js b/js/src/loaders/SpotFixSVGLoader.js index 62b61f2..892d977 100644 --- a/js/src/loaders/SpotFixSVGLoader.js +++ b/js/src/loaders/SpotFixSVGLoader.js @@ -76,13 +76,6 @@ class SpotFixSVGLoader { `; } -// static logoDoBoardWhite() { -// return ` -// -// -// `; -// } - static logoDoBoardWrap() { return ` From bc86034943e146d31a77307b5520c94fa37dd604 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Sat, 27 Dec 2025 21:08:00 +0400 Subject: [PATCH 19/20] Fix. Edits based on comments from the review --- dist/doboard-widget-bundle.js | 2 +- dist/doboard-widget-bundle.min.js | 4 ++-- dist/doboard-widget-bundle.min.js.map | 2 +- styles/doboard-widget.css | 13 ------------- 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index d55fb6d..6738f3b 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -2116,7 +2116,6 @@ function ksesFilter(html, options = false) { return doc.body.innerHTML; } -let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget a{text-decoration:underline;color:#2F68B7}.doboard_task_widget a:hover{text-decoration:none}.doboard_task_widget{position:fixed;right:50px;bottom:20px;z-index:9999;vertical-align:middle;transition:top .1s;transform:translateZ(0);-webkit-transform:translateZ(0);will-change:transform}.doboard_task_widget_cursor-pointer{cursor:pointer}.doboard_task_widget-container-maximize{width:80vw!important;max-width:1120px!important;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-container{width:430px;max-height:calc(100vh - 40px);display:flex;flex-direction:column;-moz-flex-direction:column}@media (max-height:800px){.doboard_task_widget-container,.doboard_task_widget-container-maximize{max-height:calc(60vh - 40px)}}.doboard_task_widget-header{display:flex;height:41px;min-height:41px;padding:0 16px;background-color:#EBF0F4;border-radius:8px 8px 0 0;border:1px solid #BBC7D1;border-bottom:none;justify-content:space-between;align-items:center;color:#FFF}.doboard_task_widget-user_menu-header{display:flex;padding:16px;border:1px solid #BBC7D1;border-bottom-color:#EBF0F4;border-radius:8px 8px 0 0;flex-direction:column;align-items:center;color:#252A2F;background-color:#F3F6F9}.doboard_task_widget-user_menu-header-top{display:flex;height:fit-content;align-items:center;width:100%;justify-content:space-between}.doboard_task_widget-user_menu-header-avatar{max-width:60px;max-height:60px;width:60px;height:60px;border-radius:50%;margin-bottom:4px}.doboard_task_widget-user_menu-item{display:flex;align-items:center;border-bottom:1px #EBF0F4 solid;padding:0 16px;height:65px}.doboard_task_widget-content{flex:1;overflow-y:auto;background:#FFF;border-radius:0 0 8px 8px;border:1px #BBC7D1;border-style:none solid solid;box-shadow:0 4px 15px 8px #CACACA40;scrollbar-width:none;max-height:60vh}.doboard_task_widget-element-container{margin-bottom:30px}.doboard_task_widget-wrap{box-shadow:none;position:fixed;right:-50px;padding:0;cursor:pointer;width:69px;height:52px;border-top-left-radius:4px;border-bottom-left-radius:4px;background-color:rgba(255,255,255,.9);border:1px solid #EBF0F4;display:flex;align-items:center;justify-content:center}.doboard_task_widget-input-container.hidden,.doboard_task_widget-login.hidden,.doboard_task_widget-wrap.hidden,.wrap_review::after{display:none}.doboard_task_widget-wrap img{width:32px;height:32px;transform:scaleX(-1)}.wrap_review{width:164px;min-width:164px;height:54px}.wrap_review img{width:28px;height:28px;transform:scaleX(-1)}.wrap_review:hover{background-color:#fff}@media (max-width:480px){.doboard_task_widget-wrap{right:-20px}}#review_content_button_text{color:#D5991A;margin-left:6px;font-weight:600;font-size:14px;text-transform:none!important}#doboard_task_widget-task_count{position:absolute;top:-12px;right:4px;width:22px;height:22px;opacity:1;background:#ef8b43;border-radius:50%;color:#FFF;text-align:center;line-height:22px}#doboard_task_widget-task_count.hidden{width:0;height:0;opacity:0}.doboard_task_widget-input-container{position:relative;margin-bottom:24px}.doboard_task_widget-input-container .doboard_task_widget-field{padding:0 8px;border-radius:4px;border:1px solid #BBC7D1;outline:0!important;appearance:none;width:100%;height:40px;background:#FFF;color:#000;max-width:-webkit-fill-available;max-width:-moz-available}.doboard_task_widget-field:focus{border-color:#2F68B7}.doboard_task_widget-input-container textarea.doboard_task_widget-field{height:94px;padding-top:11px;padding-bottom:11px}.doboard_task_widget-field+label{color:#252A2F;background:#fff;position:absolute;top:20px;left:8px;transform:translateY(-50%);transition:all .2s ease-in-out}.doboard_task_widget-field.has-value+label,.doboard_task_widget-field:focus+label{font-size:10px;top:0;left:12px;padding:0 4px;z-index:5}.doboard_task_widget-field:focus+label{color:#2F68B7}.doboard_task_widget-login{background:#F9FBFD;border:1px solid #BBC7D1;border-radius:4px;padding:11px 8px 8px;margin-bottom:24px}.doboard_task_widget-login .doboard_task_widget-accordion{height:0;overflow:hidden;opacity:0;transition:all .2s ease-in-out}.doboard_task_widget-login.active .doboard_task_widget-accordion{height:auto;overflow:visible;opacity:1}.doboard_task_widget-login .doboard_task_widget-input-container:last-child{margin-bottom:0}.doboard_task_widget-login span{display:block;position:relative;padding-right:24px;cursor:pointer}.doboard_task_widget-login.active span{margin-bottom:24px}.doboard_task_widget-login span::after{position:absolute;top:0;right:4px;content:"";display:block;width:10px;height:10px;transform:rotate(45deg);border:2px solid #40484F;border-radius:1px;border-top:none;border-left:none;transition:all .2s ease-in-out}.doboard_task_widget-login.active span::after{transform:rotate(-135deg);top:7px}.doboard_task_widget-login .doboard_task_widget-field+label,.doboard_task_widget-login .doboard_task_widget-input-container .doboard_task_widget-field{background:#F9FBFD}.doboard_task_widget-submit_button{height:48px;width:100%;max-width:400px;margin-bottom:10px;color:#FFF;background:#22A475;border:none;border-radius:6px;font-family:Inter,sans-serif;font-weight:700;font-size:16px;line-height:150%;cursor:pointer;transition:all .2s ease-in-out}.doboard_task_widget-submit_button:hover{background:#1C7857;color:#FFF}.doboard_task_widget-submit_button:disabled{background:rgba(117,148,138,.92);color:#FFF;cursor:wait}.doboard_task_widget-issue-title{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.doboard_task_widget-hidden_element{opacity:0}.doboard_task_widget-message-wrapper{border-radius:4px;padding:8px;margin-bottom:14px;display:grid;justify-items:center}.doboard_task_widget-error_message-wrapper.hidden,.doboard_task_widget-message-wrapper.hidden{display:none}.doboard_task_widget-error_message{background:#fdd;border:1px solid #cf6868}.doboard_task_widget-notice_message{background:#dde9ff;border:1px solid #68a6cf}#doboard_task_widget-error_message-header{font-weight:600}#doboard_task_widget-error_message{text-align:center}.doboard_task_widget-task_row{display:flex;max-height:55px;cursor:pointer;align-items:center;justify-content:space-between;padding:1px 15px}.doboard_task_widget-task_row:last-child{margin-bottom:0}.doboard_task_widget-task-text_bold{font-weight:700}.doboard_task_widget-element_selection,.doboard_task_widget-image_selection,.doboard_task_widget-text_selection,.doboard_task_widget-text_selection.image-highlight>img{background:rgba(208,213,127,.68)}.doboard_task_widget-issues_list_empty{text-align:center;margin:20px 0}.doboard_task_widget-avatar_container{display:flex;height:44px;width:44px;border-radius:50%;background-repeat:no-repeat;background-position:center;background-size:100%}.doboard_task_widget-comment_data_owner .doboard_task_widget-avatar_container{opacity:0}.doboard_task_widget-avatar_placeholder{min-height:44px;min-width:44px;border-radius:50%;font-size:24px;line-height:1.2083333333;padding:0;background:#1C7857;display:inline-grid;align-content:center;justify-content:center}.doboard_task_widget-avatar-initials{color:#FFF;width:inherit;text-align:center}.doboard_task_widget-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover}.doboard_task_widget-description_container{height:55px;width:calc(100% - 44px - 8px);border-bottom:1px solid #EBF0F4;display:block;margin-left:8px}.doboard_task_widget-task_row:last-child .doboard_task_widget-description_container{border-bottom:none}.doboard_task_widget-all_issues{padding-bottom:0}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{overflow:auto;max-height:85vh;display:none}.doboard_task_widget-task_last_message,.doboard_task_widget-task_page_url a,.doboard_task_widget-task_title span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.doboard_task_widget-all_issues-container{scrollbar-width:none;margin-top:10px}.doboard_task_widget-content.doboard_task_widget-concrete_issue{padding:0}.doboard_task_widget-concrete_issues-container{padding:10px 16px 5px}.doboard_task_widget-all_issues-container::-webkit-scrollbar,.doboard_task_widget-all_issues::-webkit-scrollbar,.doboard_task_widget-concrete_issues-container::-webkit-scrollbar,.doboard_task_widget-content::-webkit-scrollbar{width:0}.doboard_task_widget-task_title{font-weight:700;display:flex;justify-content:space-between;align-items:center}.doboard_task_widget-task_title span{font-weight:700;display:inline-block}.doboard_task_widget-task_title-details{display:flex;max-width:calc(100% - 40px);align-items:center}.doboard_task_widget-task_title-unread_block{opacity:0;height:8px;width:8px;background:#f08c43;border-radius:50%;display:inline-block;font-size:8px;font-weight:600;position:relative}.doboard_task_widget-task_title-unread_block.unread{opacity:1}.doboard_task_widget-task_last_message{max-width:85%;height:36px}.doboard_task_widget-task_page_url{max-width:70%;height:36px;display:flex;align-items:center}.doboard_task_widget-task_page_url a{color:#40484F;text-decoration:none;margin-left:8px;max-width:100%}.doboard_task_widget-bottom{display:flex;justify-content:space-between}.doboard_task_widget-bottom-is-fixed{border-radius:10px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHZpZXdCb3g9IjAgMCAxOSAxOSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik03LjA4MTE5IDAuMjIzNDM0QzguOTkxNjkgLTAuMjA4MTY3IDEwLjk5MTMgLTAuMDExMjE5NCAxMi43ODA0IDAuNzg1OTM0QzEzLjE1ODQgMC45NTQ2MjQgMTMuMzI4NiAxLjM5ODAzIDEzLjE2MDMgMS43NzYxN0MxMi45OTE3IDIuMTU0MTkgMTIuNTQ4MiAyLjMyNDI0IDEyLjE3MDEgMi4xNTYwNUMxMC42NzY0IDEuNDkwNTIgOS4wMDcyNiAxLjMyNiA3LjQxMjI1IDEuNjg2MzJDNS44MTcxNyAyLjA0NjcxIDQuMzgwOTcgMi45MTI5NiAzLjMxODUgNC4xNTYwNUMyLjI1NjIzIDUuMzk5MDEgMS42MjQ0MSA2Ljk1MjI5IDEuNTE2NzQgOC41ODM3OUMxLjQwOTI0IDEwLjIxNTQgMS44MzE4NCAxMS44MzkgMi43MjE4MiAxMy4yMTA3QzMuNjExNzkgMTQuNTgyMiA0LjkyMTY0IDE1LjYyOTQgNi40NTUyMSAxNi4xOTYxQzcuOTg5MDIgMTYuNzYyNiA5LjY2NTUzIDE2LjgxODkgMTEuMjMzNSAxNi4zNTUzQzEyLjgwMTYgMTUuODkxNiAxNC4xNzgzIDE0LjkzMzUgMTUuMTU3NCAxMy42MjM4QzE2LjEzNjQgMTIuMzE0MiAxNi42NjYxIDEwLjcyMjcgMTYuNjY3MSA5LjA4NzY5TDE4LjE2NzEgOS4wODg2N0MxOC4xNjU4IDExLjA0NzEgMTcuNTMxMiAxMi45NTM2IDE2LjM1ODUgMTQuNTIyM0MxNS4xODU5IDE2LjA5MDcgMTMuNTM3MyAxNy4yMzg0IDExLjY1OTMgMTcuNzkzN0M5Ljc4MTEgMTguMzQ5MSA3Ljc3MjkzIDE4LjI4MiA1LjkzNTY4IDE3LjYwMzNDNC4wOTg1IDE2LjkyNDYgMi41MjkxMiAxNS42NzAxIDEuNDYzMDMgMTQuMDI3MUMwLjM5NzAzNSAxMi4zODQxIC0wLjEwOTEwOSAxMC40Mzk1IDAuMDE5NjY4MyA4LjQ4NTE1QzAuMTQ4NjA3IDYuNTMwOCAwLjkwNjMyMyA0LjY3MDMzIDIuMTc4ODUgMy4xODE0NEMzLjQ1MTM2IDEuNjkyNjggNS4xNzA4OCAwLjY1NTE2MiA3LjA4MTE5IDAuMjIzNDM0WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPHBhdGggZD0iTTE2Ljg4NTkgMS44OTA0M0MxNy4xNzg2IDEuNTk3NTMgMTcuNjUzNCAxLjU5Nzg0IDE3Ljk0NjQgMS44OTA0M0MxOC4yMzkzIDIuMTgzMTYgMTguMjQwMSAyLjY1Nzk2IDE3Ljk0NzQgMi45NTA5N0w5LjYxMzQyIDExLjI5MjhDOS40NzI4MiAxMS40MzMzIDkuMjgxOTYgMTEuNTEyNCA5LjA4MzE1IDExLjUxMjVDOC44ODQzMiAxMS41MTI1IDguNjkzNDggMTEuNDMzMyA4LjU1Mjg3IDExLjI5MjhMNi4wNTI4NyA4Ljc5Mjc3QzUuNzYwMTQgOC40OTk5IDUuNzYwMTEgOC4wMjUwOCA2LjA1Mjg3IDcuNzMyMjJDNi4zNDU3MiA3LjQzOTM3IDYuODIwNTEgNy40Mzk0NiA3LjExMzQyIDcuNzMyMjJMOS4wODIxNyA5LjcwMDk3TDE2Ljg4NTkgMS44OTA0M1oiIGZpbGw9IiMyMkE0NzUiLz4NCjxwYXRoIGQ9Ik0xNy40MTcxIDcuNTcxMDlDMTcuODMxIDcuNTcxNDQgMTguMTY3IDcuOTA3MTYgMTguMTY3MSA4LjMyMTA5VjkuMDg4NjdMMTcuNDE3MSA5LjA4NzY5SDE2LjY2NzFWOC4zMjEwOUMxNi42NjcyIDcuOTA2OTQgMTcuMDAzIDcuNTcxMDkgMTcuNDE3MSA3LjU3MTA5WiIgZmlsbD0iIzIyQTQ3NSIvPg0KPC9zdmc+) 8px center no-repeat #EBFAF4;padding:4px 7px 4px 30px}.doboard_task_widget-bottom-is-fixed-task-block{text-align:center}.doboard_task_widget-bottom-is-fixed-task{background:#F3F6F9;color:#1C7857;display:inline-block;border-radius:10px;padding:5px 8px;margin:0 auto}.doboard_task_widget-task_row-green{background:#EBF0F4}.doboard_task_widget_return_to_all{display:flex;gap:8px;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:wrap}.doboard_task_widget-task_title-last_update_time{font-family:Inter,serif;font-weight:400;font-style:normal;font-size:11px;leading-trim:NONE;line-height:100%}.doboard_task_widget-task_title_public_status_img{opacity:50%;margin-left:5px;scale:90%}.doboard_task_widget-description-textarea{resize:none}.doboard_task_widget-switch_row{display:flex;align-items:center;gap:12px;margin:16px 0;justify-content:space-between}.doboard_task_widget-switch-label{font-weight:600;font-size:16px;height:24px;align-content:center}.doboard_task_widget-switch{position:relative;display:inline-block;width:44px;height:24px;flex-shrink:0}.doboard_task_widget-switch input{opacity:0;width:0;height:0}.doboard_task_widget-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;border-radius:24px;transition:.2s}.doboard_task_widget-slider:before{position:absolute;content:"";height:20px;width:20px;left:2px;bottom:2px;background-color:#fff;border-radius:50%;transition:.2s}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider{background-color:#65D4AC}.doboard_task_widget-switch input:checked+.doboard_task_widget-slider:before{transform:translateX(20px)}.doboard_task_widget-switch-img{width:24px;height:24px;flex-shrink:0}.doboard_task_widget-switch-center{display:flex;gap:2px;flex-direction:column;-moz-flex-direction:column;flex:1 1 auto;min-width:0}.doboard_task_widget-switch-desc{display:block;font-size:12px;color:#707A83;margin:0;line-height:1.2;max-width:180px;word-break:break-word}.doboard_task_widget-concrete_issue-day_content{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-concrete_issue_day_content-month_day{text-align:center;font-weight:400;font-size:12px;line-height:100%;padding:8px;opacity:.75}.doboard_task_widget-concrete_issue_day_content-messages_wrapper{display:flex;flex-direction:column;-moz-flex-direction:column}.doboard_task_widget-comment_data_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;margin-bottom:15px;align-items:flex-end}.doboard_task_widget-comment_text_container{position:relative;width:calc(100% - 44px - 5px);height:auto;margin-left:5px;background:#F3F6F9;border-radius:16px}.doboard_task_widget-comment_text_container:after{content:"";position:absolute;bottom:0;left:-5px;width:13px;height:19px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAxMyAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTEyNTggMTkuMDMzNEM1LjI5NDg2IDE5LjgyMDEgMTAuNjEwNSAxNy45NzQxIDEyLjI3MTUgMTYuMTcxM0MxMi4yNzE1IDE2LjE3MTMgMTAuOTYyMyAtMi43ODEyNCA1LjA5NTU0IDAuMzQ5MDc5QzUuMDc0NCAxLjYxNDU0IDUuMDk1NTQgNS45OTQ5IDUuMDk1NTQgNi43NDA2OUM1LjA5NTU0IDE3LjA2NjIgLTAuODg0MDEyIDE4LjQ0MDEgMC4xMTI1OCAxOS4wMzM0WiIgZmlsbD0iI0YzRjZGOSIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container{background:#EBFAF4}.doboard_task_widget-comment_data_owner .doboard_task_widget-comment_text_container:after{left:auto;right:-5px;height:13px;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTMiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMyAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyLjc3NzEgMTIuMzA2NkM3LjMzMTM1IDEzLjA5MzcgMS43NDU0NCAxMS4yNDY5IDAgOS40NDMxOUw3LjM5MTYgMEM3LjM5MTYgMTAuMzMwMyAxMy44MjQ0IDExLjcxMzEgMTIuNzc3MSAxMi4zMDY2WiIgZmlsbD0iI0VCRkFGNCIvPgo8L3N2Zz4K)}.doboard_task_widget-comment_body,.doboard_task_widget-comment_time{position:relative;z-index:1}.doboard_task_widget-comment_body{padding:6px 8px;min-height:30px}.doboard_task_widget-comment_body strong{font-variation-settings:"wght" 700}.doboard_task_widget-comment_body blockquote{margin:0;border-left:3px solid #22a475}.doboard_task_widget-comment_body blockquote p{margin:0 10px}.doboard_task_widget-comment_body details .mce-accordion-body{padding-left:20px}.doboard_task_widget-comment_body details .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg transform='rotate(180 0 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat;padding-left:20px}.doboard_task_widget-comment_body .mce-accordion[open] .mce-accordion-summary{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' style='enable-background:new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M10 13.3c-.2 0-.4-.1-.6-.2l-5-5c-.3-.3-.3-.9 0-1.2.3-.3.9-.3 1.2 0l4.4 4.4 4.4-4.4c.3-.3.9-.3 1.2 0 .3.3.3.9 0 1.2l-5 5c-.2.2-.4.2-.6.2z'/%3E%3C/svg%3E") 0 no-repeat}.doboard_task_widget-comment_body details .mce-accordion-summary::marker{content:""}.doboard_task_widget-comment_body pre{border:1px solid #d6dde3;border-left-width:8px;border-radius:4px;padding:13px 16px 14px 12px;white-space:pre-wrap}.doboard_task_widget-comment_time{font-weight:400;font-size:11px;opacity:.8;position:absolute;bottom:6px;right:6px}.doboard_task_widget-comment_body-img-strict{max-width:-webkit-fill-available;height:100px;margin-right:5px}.doboard_task_widget-send_message{padding:14px 10px;border-top:1px solid #BBC7D1;position:sticky;background:#fff;bottom:0;z-index:4}.doboard_task_widget-send_message_elements_wrapper{display:flex;flex-direction:row;-moz-flex-direction:row;align-content:center;flex-wrap:nowrap;justify-content:space-between;align-items:end}.doboard_task_widget-send_message_elements_wrapper button{height:37px;background:0 0;margin:0}.doboard_task_widget-send_message_elements_wrapper img{margin:0}.doboard_task_widget-send_message_input_wrapper{position:relative;display:inline-grid;align-items:center;justify-items:center;flex-grow:1;padding:0 6px}.doboard_task_widget-send_message_input_wrapper textarea{position:relative;width:100%;height:37px;border:none;outline:0;box-shadow:none;border-radius:24px;background:#F3F6F9;resize:none;margin-bottom:0!important;transition:height .2s ease-in-out;padding:8px;box-sizing:border-box}.doboard_task_widget-send_message_input_wrapper textarea.high{height:170px}.doboard_task_widget-send_message_input_wrapper textarea:focus{background:#F3F6F9;border-color:#007bff;outline:0}.doboard_task_widget-send_message_button,.doboard_task_widget-send_message_paperclip{display:inline-grid;border:none;background:0 0;cursor:pointer;padding:0;align-items:center;margin:0}.doboard_task_widget-send_message_button:hover,.doboard_task_widget-send_message_paperclip:hover rect{fill:#45a049}.doboard_task_widget-send_message_button:active,.doboard_task_widget-send_message_paperclip:active{transform:scale(.98)}.doboard_task_widget-spinner_wrapper_for_containers{display:flex;justify-content:center;align-items:center;min-height:60px;width:100%}.doboard_task_widget-spinner_for_containers{width:40px;height:40px;border-radius:50%;background:conic-gradient(transparent,#1C7857);mask:radial-gradient(farthest-side,transparent calc(100% - 4px),#fff 0);animation:spin 1s linear infinite}.doboard_task_widget-create_issue{padding:10px}.doboard_task_widget__file-upload__wrapper{display:none;border:1px solid #BBC7D1;margin-top:14px;padding:0 10px 10px;border-radius:4px}.doboard_task_widget__file-upload__list-header{text-align:left;font-size:.9em;margin:5px 0;color:#444c529e}.doboard_task_widget__file-upload__file-input-button{display:none}.doboard_task_widget__file-upload__file-list{border:1px solid #ddd;border-radius:5px;padding:6px;max-height:200px;overflow-y:auto;background:#f3f6f9}.doboard_task_widget__file-upload__file-item{display:flex;justify-content:space-between;align-items:center;padding:4px;border-bottom:1px solid #bbc7d16b}.doboard_task_widget__file-upload__file-item:last-child{border-bottom:none}.doboard_task_widget__file-upload__file_info{display:inline-flex;align-items:center}.doboard_task_widget__file-upload__file-name{font-weight:700;font-size:.9em}.doboard_task_widget__file-upload__file-item-content{width:100%}.doboard_task_widget__file-upload__file_size{color:#666;font-size:.8em;margin-left:6px}.doboard_task_widget__file-upload__remove-btn{background:#22a475;color:#fff;border:none;border-radius:3px;cursor:pointer}.doboard_task_widget__file-upload__error{display:block;margin:7px 0 0;padding:7px;border-radius:4px;background:#fdd;border:1px solid #cf6868}.doboard_task_widget-show_button{position:fixed;background:#1C7857;color:#FFF;padding:8px 12px;border-radius:4px;font-size:14px;z-index:10000;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.3);transform:translate(-50%,-100%);margin-top:-8px;white-space:nowrap;border:none;font-family:inherit}@keyframes spin{to{transform:rotate(1turn)}}@media (max-width:480px){.doboard_task_widget{position:fixed;right:0;top:auto;bottom:0;margin:0 20px 20px;box-sizing:border-box;transform:translateZ(0);-moz-transform:translateZ(0);will-change:transform;max-height:90vh}.doboard_task_widget-header{padding:8px}.doboard_task_widget-issue-title{max-width:70px}.doboard_task_widget-container,.doboard_task_widget-container-maximize{width:100%;max-width:290px;margin:0 auto;max-height:90vh}.doboard_task_widget-content{height:auto;max-height:none;scrollbar-width:none}.doboard_task_widget-content::-webkit-scrollbar{display:none}.doboard_task_widget-all_issues-container,.doboard_task_widget-concrete_issues-container{max-height:80vh}}@supports (-webkit-overflow-scrolling:touch){.doboard_task_widget{position:fixed}}.doboard_task_widget_tasks_list{background-color:#fff;position:sticky;bottom:0;height:38px;display:flex;flex-direction:column-reverse;align-items:center;padding-bottom:8px}#doboard_task_widget-user_menu-logout_button{display:inline-flex;align-items:center}.doboard_task_widget-text_selection{position:relative;display:inline-block}.doboard_task_widget-see-task{cursor:pointer;text-decoration:underline}.doboard_task_widget-text_selection_tooltip{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);background:#FFF;color:#000;padding:4px 8px;border-radius:4px;font-size:10px;white-space:nowrap;z-index:9000;border:1px solid #BBC7D1;margin-bottom:8px}.doboard_task_widget-text_selection_tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:#FFF}.doboard_task_widget-text_selection_tooltip::before{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#BBC7D1;z-index:-1}.doboard_task_widget-text_selection_tooltip_icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDEwMyAxMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEwMyAxMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMxNzcyNTA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MywwSDB2MTAwaDMwLjJINTNDMTE5LjYsMTAwLDExOS42LDAsNTMsMHogTTMwLjIsMTAwYy0xNi42LDAtMzAtMTMuNC0zMC0zMHMxMy40LTMwLDMwLTMwDQoJYzE2LjYsMCwzMCwxMy40LDMwLDMwUzQ2LjgsMTAwLDMwLjIsMTAweiIvPg0KPC9zdmc+DQo=);background-repeat:no-repeat;width:22px;height:22px;margin:5px 3px}.doboard_task_widget-text_selection_tooltip_element{display:flex;justify-content:space-between}.toggle{position:relative;display:inline-block;width:46px;height:28px}.toggle input{opacity:0;width:0;height:0;position:absolute}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#bbc7d1;border-radius:24px;transition:.3s}.slider:before{content:"";position:absolute;height:24px;width:24px;left:2px;top:2px;background-color:#fff;border-radius:50%;transition:.3s}input:checked+.slider{background-color:#65d4ac}input:checked+.slider:before{transform:translateX(16px)}.logout_button{font-weight:500;font-size:14px;color:#707A83;cursor:pointer}`; /** * SELECTION will be grouped into three types: * 1 - Simple text within a single tag @@ -2676,6 +2675,7 @@ function spotFixRetrieveNodeFromPath(path) { return node; } +let spotFixCSS = `.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip::after{content:"";position:absolute;left:8%;top:100%;transform:translateX(-50%);pointer-events:none;background:0 0;border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #545b61;display:block}.doboard_task_widget-send_message_paperclip{position:relative}.doboard_task_widget-send_message_paperclip .doboard_task_widget-paperclip-tooltip{display:none;position:absolute;left:0;bottom:0;transform:translateX(-3%) translateY(-43px);background:#545b61;color:#FFF;border:none;border-radius:3px;padding:10px 16px;font-size:13px;line-height:1.4;z-index:100;min-width:220px;max-width:320px;text-align:left;pointer-events:none;text-transform:none}.doboard_task_widget-send_message_paperclip:hover .doboard_task_widget-paperclip-tooltip{display:block}.doboard_task_widget *{font-family:Inter,sans-serif;font-weight:400;font-size:14px;line-height:130%;color:#40484F}.doboard_task_widget-header *{color:#252A2F;margin:0}.doboard_task_widget 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}`; /** * Return bool if widget is closed in local storage * @returns {boolean} diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index ec6a422..5a14db2 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,10 +1,10 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&clearLocalstorageOnLogout()},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


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


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e&&(e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)}))}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button")?.closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:window.location.href})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{logoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
You can see history Here
-
`}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;e{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(` + `}
`,r=e.textContent;var d=t[0].selectedText;if(d){let i=[];if(t.forEach(e=>{var t=parseInt(e.startSelectPosition)||0,a=parseInt(e.endSelectPosition)||0;t<0||a>r.length||at.position-e.position),r.slice(i[1].position,i[0].position)!==d)spotFixDebugLog("It is not allow to highlight element by provided metadata.");else{let a=r;i.forEach(e=>{var t="start"===e.type?s:"
";a=a.slice(0,e.position)+t+a.slice(e.position)});try{e.innerHTML=ksesFilter(a),document.querySelectorAll(".doboard_task_widget-see-task").forEach(a=>{a.addEventListener("click",e=>{e.preventDefault();e=a.className.split(" ").find(e=>e.includes("__task-id-"));let t=null;(t=e?e.split("__task-id-")[1]:t)&&(o.currentActiveTaskId=t,o.showOneTask())})})}catch(e){spotFixDebugLog("Error updating element content: "+e)}}}else spotFixDebugLog("Provided metadata is invalid.")}function spotFixScrollToNodePath(e){e=spotFixRetrieveNodeFromPath(e);return!(!e||!e.scrollIntoView||(e.scrollIntoView({behavior:"smooth",block:"center"}),0))}function spotFixRemoveHighlights(){var e=document.querySelectorAll(".doboard_task_widget-text_selection");let i=new Set,t=(e.forEach(e=>{var t=e.parentNode,a=(i.add(t),e.querySelector(".doboard_task_widget-text_selection_tooltip"));for(a&&a.remove();e.firstChild;)t.insertBefore(e.firstChild,e);t.removeChild(e)}),i.forEach(e=>e.normalize()),"doboard_task_widget-element_selection"),a=(document.querySelectorAll("."+t).forEach(e=>{e.classList.remove(t)}),"doboard_task_widget-image_selection");document.querySelectorAll("."+a).forEach(e=>{e.classList.remove(a)})}function spotFixIsValidNodePath(e){return!!Array.isArray(e)&&0!==e.length&&e.every(e=>Number.isInteger(e)&&0<=e&&e<1e3)}function spotFixGetSelectedImage(e){if(e&&0!==e.rangeCount&&!e.isCollapsed){let t=e.getRangeAt(0);if(t.startContainer===t.endContainer&&t.startContainer.nodeType===Node.ELEMENT_NODE&&"IMG"===t.startContainer.tagName)return t.startContainer;e=document.createTreeWalker(t.commonAncestorContainer,NodeFilter.SHOW_ELEMENT,{acceptNode:function(e){return"IMG"===e.tagName&&spotFixIsElementInRange(e,t)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}).nextNode();if(e)return e;var a,e=spotFixGetElementFromNode(t.startContainer),i=spotFixGetElementFromNode(t.endContainer);if(e&&"IMG"===e.tagName&&spotFixIsElementPartiallySelected(e,t))return e;if(i&&"IMG"===i.tagName&&spotFixIsElementPartiallySelected(i,t))return i;for(a of spotFixFindNearbyElements(t))if("IMG"===a.tagName)return a}return null}function spotFixIsElementInRange(e,t){var a=document.createRange();return a.selectNode(e),t.compareBoundaryPoints(Range.START_TO_START,a)<=0&&0<=t.compareBoundaryPoints(Range.END_TO_END,a)}function spotFixIsElementPartiallySelected(e,t){e=e.getBoundingClientRect(),t=t.getBoundingClientRect();return!(e.rightt.right||e.bottomt.bottom)}function spotFixGetElementFromNode(e){return e.nodeType===Node.ELEMENT_NODE?e:e.parentElement}function spotFixFindNearbyElements(t){var a=[],e=t.commonAncestorContainer,i=e.previousElementSibling,o=e.nextElementSibling;if(i&&a.push(i),o&&a.push(o),e.nodeType===Node.ELEMENT_NODE){var s=e.children;for(let e=0;eimg{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}`;function storageGetWidgetIsClosed(){return"1"===localStorage.getItem("spotfix_widget_is_closed")}function storageWidgetCloseIsSet(){return null!==localStorage.getItem("spotfix_widget_is_closed")}function storageSetWidgetIsClosed(e){localStorage.setItem("spotfix_widget_is_closed",e?"1":"0")}function storageGetUserIsDefined(){return null!==localStorage.getItem("spotfix_user_id")}function storageSaveTasksUpdateData(e){if(e&&Array.isArray(e)){let t={};try{t=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){t={}}e.forEach(e=>{e.taskId&&e.taskLastUpdate&&(t[e.taskId]={taskId:e.taskId,taskLastUpdate:e.taskLastUpdate})}),localStorage.setItem("spotfix_task_updates",JSON.stringify(t))}}function storageSaveTasksCount(e){e&&Array.isArray(e)&&(e=e.filter(e=>e.taskMeta)?.length,localStorage.setItem("spotfix_tasks_count",""+e))}function storageCheckTaskUpdate(e,t){if(!e||!t)return null;let a={};try{a=JSON.parse(localStorage.getItem("spotfix_task_updates")||"{}")}catch(e){a={}}e=a[e];return!!e&&new Date(e.taskLastUpdate)e!==a),localStorage.setItem("spotfix_unread_updates",JSON.stringify(t))}}function storageTasksHasUnreadUpdates(){let t=[];try{t=JSON.parse(localStorage.getItem("spotfix_unread_updates")||"[]")}catch(e){t=[]}return 0this.handleFileInputChange(e))}bindPaperClipAction(e){e.addEventListener("click",e=>{e.preventDefault(),this.fileInput&&this.fileInput.click()})}handleFileInputChange(e){this.clearError();var t=Array.from(e.target.files);this.files.length+t.length>this.maxFiles?this.showError(`Maximum ${this.maxFiles} files can be attached.`):(t.filter(e=>this.validateFile(e)).forEach(e=>this.addFile(e)),e.target.value="",this.uploaderWrapper.style.display="block")}validateFile(e){return e.size>this.maxFileSize?(this.showError(`File "${e.name}" is too large. Maximum size: `+this.formatFileSize(this.maxFileSize)),!1):this.getTotalSize()+e.size>this.maxTotalSize?(this.showError("Total files size exceeded. Maximum: "+this.formatFileSize(this.maxTotalSize)),!1):!(0e+t.file.size,0)}addFile(e){e={id:this.generateFileId(),file:e};this.files.push(e),this.renderFileList()}generateFileId(){return Date.now()+Math.random().toString(36).substr(2,9)}removeFile(t){this.files=this.files.filter(e=>e.id!==t),this.renderFileList(),this.clearError()}renderFileList(){var e;this.fileList&&(0===this.files.length?this.fileList.innerHTML=ksesFilter('
No files attached
'):(e=this.files.map(e=>this.createFileItem(e)),this.fileList.innerHTML=ksesFilter(""),e.forEach(e=>this.fileList.appendChild(e))))}createFileItem(e){let{file:t,id:a}=e;e=document.createElement("div");return e.className="doboard_task_widget__file-upload__file-item",e.innerHTML=ksesFilter(`
${this.escapeHtmlHandler(String(t.name))}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index f0420ad..e9273ca 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: '',\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 || '';\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\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 * SELECTION will be grouped into three types:\r\n * 1 - Simple text within a single tag\r\n * 2 - Image tags\r\n * 3 - Any tag containing nested content\r\n * Each type will be processed differently.\r\n */\r\nconst SPOTFIX_SELECTION_TYPE_TEXT = 'text';\r\nconst SPOTFIX_SELECTION_TYPE_IMG = 'image';\r\nconst SPOTFIX_SELECTION_TYPE_ELEMENT = 'element';\r\n\r\n/**\r\n * Determines the type of selection\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {string|null} Selection type\r\n */\r\nfunction spotFixGetSelectionType(selection) {\r\n const range = selection.getRangeAt(0);\r\n const commonAncestor = range.commonAncestorContainer;\r\n\r\n // Case 1: Image selection\r\n if (spotFixGetSelectedImage(selection)) {\r\n return SPOTFIX_SELECTION_TYPE_IMG;\r\n }\r\n\r\n // Case 2: Element with nested content\r\n if (commonAncestor.nodeType === Node.ELEMENT_NODE &&\r\n commonAncestor.childNodes.length > 1 &&\r\n range.toString().trim() === '' &&\r\n range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE) {\r\n return SPOTFIX_SELECTION_TYPE_ELEMENT;\r\n }\r\n\r\n // Case 3: Simple text\r\n const hasTextContent = range.toString().trim().length > 0;\r\n const isTextNode = commonAncestor.nodeType === Node.TEXT_NODE;\r\n const isCollapsed = range.collapsed;\r\n\r\n if (hasTextContent && (isTextNode || !isCollapsed)) {\r\n return SPOTFIX_SELECTION_TYPE_TEXT;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extracts selection data from DOM Selection object\r\n * @param {Selection} selection - The DOM Selection object\r\n * @returns {Object|null} Selection data with text, positions, URL and node path OR null (nothing)\r\n */\r\nfunction spotFixGetSelectedData(selection) {\r\n // Prechecks:\r\n // Selection not provided\r\n if (!selection) {spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection not provided`'); return null; }\r\n // Range not provided\r\n if (selection.rangeCount === 0) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Range not provided`'); return null; }\r\n // Several ranges provided\r\n if (selection.rangeCount > 1) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Several ranges provided`'); return null; }\r\n\r\n const range = selection.getRangeAt(0);\r\n // Selection must be within a single DOM element.\r\n if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }\r\n\r\n // FIRST - check selection type\r\n const selectionType = spotFixGetSelectionType(selection);\r\n\r\n // Selection type not determined\r\n if (!selectionType) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection type not determined`'); return null; }\r\n\r\n // SECOND - generate selectedData for each selectionType\r\n let selectedText = '';\r\n let startSelectPosition = 0;\r\n let endSelectPosition = 0;\r\n let nodePath = '';\r\n let imageUrl = '';\r\n\r\n const commonNode = range.commonAncestorContainer;\r\n\r\n switch (selectionType) {\r\n case SPOTFIX_SELECTION_TYPE_TEXT:\r\n if (range.toString().trim().length === 0) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection text is empty`');\r\n return null;\r\n }\r\n const commonNodeElement = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n selectedText = range.toString();\r\n startSelectPosition = range.startOffset;\r\n endSelectPosition = range.endOffset;\r\n if ( startSelectPosition === 0 && selectedText.length > endSelectPosition ) {\r\n endSelectPosition = selectedText.length;\r\n }\r\n nodePath = spotFixCalculateNodePath(commonNodeElement);\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_IMG:\r\n const imgElement = range.startContainer;\r\n const selectedImage = spotFixGetSelectedImage(selection);\r\n selectedText = `Image (${selectedImage.alt ? selectedImage.alt : 'no description'})`;\r\n nodePath = spotFixCalculateNodePath(selectedImage);\r\n // For images, positions represent the image element position in parent\r\n startSelectPosition = Array.from(imgElement.parentNode.children).indexOf(imgElement);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n\r\n case SPOTFIX_SELECTION_TYPE_ELEMENT:\r\n const element = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;\r\n if (element.childNodes.length <= 1) {\r\n spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection have not inner data`');\r\n return null;\r\n }\r\n selectedText = element.textContent || '';\r\n nodePath = spotFixCalculateNodePath(element);\r\n // For elements, positions represent the element's position in parent\r\n startSelectPosition = Array.from(element.parentNode.children).indexOf(element);\r\n endSelectPosition = startSelectPosition + 1;\r\n break;\r\n }\r\n\r\n // Get page URL\r\n const pageURL = window.location.href;\r\n\r\n return {\r\n startSelectPosition,\r\n endSelectPosition,\r\n selectedText: selectedText.trim(),\r\n pageURL,\r\n nodePath,\r\n selectionType,\r\n imageUrl: selectionType === SPOTFIX_SELECTION_TYPE_IMG ? imageUrl : ''\r\n };\r\n}\r\n\r\n/**\r\n * Highlight elements.\r\n * @param {[object]} spotsToBeHighlighted\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightElements(spotsToBeHighlighted, widgetInstance) {\r\n\r\n if (spotsToBeHighlighted.length === 0) return;\r\n\r\n const elementsMap = new Map();\r\n\r\n // Grouping elements with validation\r\n spotsToBeHighlighted.forEach(spot => {\r\n // nodePath validating: is array\r\n if (!spot?.nodePath || !Array.isArray(spot?.nodePath)) {\r\n spotFixDebugLog('Invalid spot: missing or invalid nodePath: ' + spot);\r\n return;\r\n }\r\n\r\n // nodePath validating: is valid indexes list\r\n if (!this.spotFixIsValidNodePath(spot.nodePath)) {\r\n spotFixDebugLog('Invalid nodePath format: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n const element = spotFixRetrieveNodeFromPath(spot.nodePath);\r\n if (!element) {\r\n spotFixDebugLog('Element not found for path: ' + spot.nodePath);\r\n return;\r\n }\r\n\r\n if ( ! spot.selectionType ) {\r\n // @ToDo need to apply backward capability here\r\n // just `spot.selectionType = 'text';` is not able, this opens ability to unauthorized modify website content\r\n spotFixDebugLog('Selection type is not provided.');\r\n return;\r\n }\r\n\r\n // selectionType parameter validating\r\n if (\r\n spot.selectionType &&\r\n ![\r\n SPOTFIX_SELECTION_TYPE_TEXT,\r\n SPOTFIX_SELECTION_TYPE_IMG,\r\n SPOTFIX_SELECTION_TYPE_ELEMENT\r\n ].includes(spot.selectionType)\r\n ) {\r\n spotFixDebugLog('Invalid selection type: ' + spot.selectionType);\r\n return;\r\n }\r\n\r\n if (!elementsMap.has(element)) {\r\n elementsMap.set(element, []);\r\n }\r\n elementsMap.get(element).push(spot);\r\n });\r\n\r\n elementsMap.forEach((spots, element) => {\r\n const selectionType = spots[0].selectionType;\r\n\r\n // MAIN LOGIC: highlight for the different types\r\n switch (selectionType) {\r\n case 'image':\r\n this.spotFixHighlightImageElement(element);\r\n break;\r\n\r\n case 'element':\r\n this.spotFixHighlightNestedElement(element);\r\n break;\r\n\r\n case 'text':\r\n this.spotFixHighlightTextInElement(element, spots, widgetInstance);\r\n break;\r\n\r\n default:\r\n spotFixDebugLog('Unknown selection type: ' + selectionType);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Highlight image element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightImageElement(element) {\r\n if (element.tagName !== 'IMG') {\r\n spotFixDebugLog('Expected IMG element for image highlight, got: ' + element.tagName);\r\n return;\r\n }\r\n element.classList.add('doboard_task_widget-image_selection');\r\n}\r\n\r\n/**\r\n * Highlight nested element by adding class\r\n * @param {Element} element\r\n */\r\nfunction spotFixHighlightNestedElement(element) {\r\n element.classList.add('doboard_task_widget-element_selection');\r\n}\r\n\r\n/**\r\n * Highlight text in element with span wrapping\r\n * @param {Element} element\r\n * @param {Array} spots\r\n * @param widgetInstance\r\n */\r\nfunction spotFixHighlightTextInElement(element, spots,widgetInstance) {\r\n let tooltipTitleText = '';\r\n if (spots[0].isFixed) {\r\n tooltipTitleText = `This issue already fixed.`;\r\n } else {\r\n tooltipTitleText = `We are already working on this issue.`;\r\n }\r\n\r\n const tooltip = `
\r\n \r\n \r\n
${tooltipTitleText}
\r\n
You can see history Here
\r\n
\r\n
`;\r\n\r\n const spotfixHighlightOpen = `${tooltip}`;\r\n const spotfixHighlightClose = ``;\r\n\r\n let text = element.textContent;\r\n const spotSelectedText = spots[0].selectedText;\r\n\r\n // meta.selectedText can not be empty string\r\n if ( ! spotSelectedText ) {\r\n spotFixDebugLog('Provided metadata is invalid.');\r\n return;\r\n }\r\n\r\n const markers = [];\r\n\r\n // Mark positions for inserting\r\n spots.forEach(spot => {\r\n // Validating positions\r\n const startPos = parseInt(spot.startSelectPosition) || 0;\r\n const endPos = parseInt(spot.endSelectPosition) || 0;\r\n\r\n if (startPos < 0 || endPos > text.length || startPos > endPos) {\r\n spotFixDebugLog('Invalid text positions: ' + spot);\r\n return;\r\n }\r\n\r\n markers.push({ position: startPos, type: 'start' });\r\n markers.push({ position: endPos, type: 'end' });\r\n });\r\n\r\n if (markers.length === 0) return;\r\n\r\n // Sort markers backward\r\n markers.sort((a, b) => b.position - a.position);\r\n\r\n // Check here that element (from meta.nodePath) contains same inner text as in meta.selectedText\r\n // Is the `text` in the element equal to the selected text `spotSelectedText`\r\n if ( text.slice(markers[1].position, markers[0].position) !== spotSelectedText ) {\r\n spotFixDebugLog('It is not allow to highlight element by provided metadata.');\r\n return;\r\n }\r\n\r\n let result = text;\r\n markers.forEach(marker => {\r\n const insertText = marker.type === 'start'\r\n ? spotfixHighlightOpen\r\n : spotfixHighlightClose;\r\n\r\n result = result.slice(0, marker.position) + insertText + result.slice(marker.position);\r\n });\r\n\r\n // Safety HTML insert\r\n try {\r\n element.innerHTML = ksesFilter(result);\r\n document.querySelectorAll('.doboard_task_widget-see-task').forEach(link => {\r\n link.addEventListener('click', (e) => {\r\n\r\n e.preventDefault();\r\n const classList = link.className.split(' ');\r\n const idClass = classList.find(cls => cls.includes('__task-id-'));\r\n let taskId = null;\r\n if (idClass) {\r\n taskId = idClass.split('__task-id-')[1];\r\n }\r\n if (taskId) {\r\n widgetInstance.currentActiveTaskId = taskId;\r\n widgetInstance.showOneTask();\r\n }\r\n });\r\n });\r\n } catch (error) {\r\n spotFixDebugLog('Error updating element content: ' + error);\r\n }\r\n}\r\n\r\n/**\r\n * Scroll to an element by tag, class, and text content\r\n * @param {array} path - The path to the element\r\n * @return {boolean} - True if the element was found and scrolled to, false otherwise\r\n */\r\nfunction spotFixScrollToNodePath(path) {\r\n const node = spotFixRetrieveNodeFromPath(path);\r\n if (node && node.scrollIntoView) {\r\n node.scrollIntoView({ behavior: 'smooth', block: 'center' });\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction spotFixRemoveHighlights() {\r\n const textSelectionclassName = 'doboard_task_widget-text_selection';\r\n const spans = document.querySelectorAll('.' + textSelectionclassName);\r\n const affectedParents = new Set(); // Track unique parents\r\n\r\n spans.forEach(span => {\r\n const parent = span.parentNode;\r\n affectedParents.add(parent); // Mark parent as affected\r\n const tooltip = span.querySelector('.doboard_task_widget-text_selection_tooltip');\r\n if (tooltip) tooltip.remove();\r\n\r\n // Move all child nodes out of the span and into the parent\r\n while (span.firstChild) {\r\n parent.insertBefore(span.firstChild, span);\r\n }\r\n parent.removeChild(span);\r\n });\r\n\r\n // Normalize all affected parents to merge adjacent text nodes\r\n affectedParents.forEach(parent => parent.normalize());\r\n\r\n const elementSelectionClassName = 'doboard_task_widget-element_selection';\r\n const elements = document.querySelectorAll(`.${elementSelectionClassName}`);\r\n elements.forEach(element => {\r\n element.classList.remove(elementSelectionClassName);\r\n });\r\n const imageSelectionClassName = 'doboard_task_widget-image_selection';\r\n const images = document.querySelectorAll(`.${imageSelectionClassName}`);\r\n images.forEach(element => {\r\n element.classList.remove(imageSelectionClassName);\r\n });\r\n}\r\n\r\n/**\r\n * Validate nodePath as array of indices\r\n * @param {Array} nodePath\r\n * @returns {boolean}\r\n */\r\nfunction spotFixIsValidNodePath(nodePath) {\r\n if (!Array.isArray(nodePath)) return false;\r\n if (nodePath.length === 0) return false;\r\n\r\n return nodePath.every(index => {\r\n return Number.isInteger(index) && index >= 0 && index < 1000;\r\n });\r\n}\r\n\r\n/**\r\n * Try to find selected image in selection.\r\n * @param selection\r\n * @returns {Node|*|null}\r\n */\r\nfunction spotFixGetSelectedImage(selection) {\r\n\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\r\n return null;\r\n }\r\n\r\n const range = selection.getRangeAt(0);\r\n\r\n // Is current end container IMG\r\n if (range.startContainer === range.endContainer &&\r\n range.startContainer.nodeType === Node.ELEMENT_NODE &&\r\n range.startContainer.tagName === 'IMG') {\r\n return range.startContainer;\r\n }\r\n\r\n // Get img in the range\r\n const walker = document.createTreeWalker(\r\n range.commonAncestorContainer,\r\n NodeFilter.SHOW_ELEMENT,\r\n {\r\n acceptNode: function(node) {\r\n return node.tagName === 'IMG' &&\r\n spotFixIsElementInRange(node, range) ?\r\n NodeFilter.FILTER_ACCEPT :\r\n NodeFilter.FILTER_REJECT;\r\n }\r\n }\r\n );\r\n\r\n let imgNode = walker.nextNode();\r\n if (imgNode) {\r\n return imgNode;\r\n }\r\n\r\n // start/end containers\r\n const startElement = spotFixGetElementFromNode(range.startContainer);\r\n const endElement = spotFixGetElementFromNode(range.endContainer);\r\n\r\n // If selection starts on image\r\n if (startElement && startElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(startElement, range)) {\r\n return startElement;\r\n }\r\n\r\n if (endElement && endElement.tagName === 'IMG' &&\r\n spotFixIsElementPartiallySelected(endElement, range)) {\r\n return endElement;\r\n }\r\n\r\n // 4. Get closest IMG\r\n const nearbyElements = spotFixFindNearbyElements(range);\r\n for (const element of nearbyElements) {\r\n if (element.tagName === 'IMG') {\r\n return element;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nfunction spotFixIsElementInRange(element, range) {\r\n const elementRange = document.createRange();\r\n elementRange.selectNode(element);\r\n return range.compareBoundaryPoints(Range.START_TO_START, elementRange) <= 0 &&\r\n range.compareBoundaryPoints(Range.END_TO_END, elementRange) >= 0;\r\n}\r\n\r\nfunction spotFixIsElementPartiallySelected(element, range) {\r\n const elementRect = element.getBoundingClientRect();\r\n const rangeRect = range.getBoundingClientRect();\r\n\r\n // bounding rectangles is crossed\r\n return !(elementRect.right < rangeRect.left ||\r\n elementRect.left > rangeRect.right ||\r\n elementRect.bottom < rangeRect.top ||\r\n elementRect.top > rangeRect.bottom);\r\n}\r\n\r\nfunction spotFixGetElementFromNode(node) {\r\n return node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;\r\n}\r\n\r\n/**\r\n * Find nearby elements in the range.\r\n * @param range\r\n * @returns {*[]}\r\n */\r\nfunction spotFixFindNearbyElements(range) {\r\n const elements = [];\r\n const container = range.commonAncestorContainer;\r\n\r\n // search elements\r\n const previousElement = container.previousElementSibling;\r\n const nextElement = container.nextElementSibling;\r\n\r\n if (previousElement) {\r\n elements.push(previousElement);\r\n }\r\n if (nextElement) {\r\n elements.push(nextElement);\r\n }\r\n\r\n // Also check child container\r\n if (container.nodeType === Node.ELEMENT_NODE) {\r\n const children = container.children;\r\n for (let i = 0; i < children.length; i++) {\r\n if (spotFixIsElementPartiallySelected(children[i], range)) {\r\n elements.push(children[i]);\r\n }\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n\r\n/**\r\n * Calculate the path of a DOM node\r\n *\r\n * @param {Node} node\r\n * @return {int[]}\r\n */\r\nfunction spotFixCalculateNodePath(node) {\r\n let path = [];\r\n while (node) {\r\n let index = 0;\r\n let sibling = node.previousSibling;\r\n while (sibling) {\r\n if (sibling.nodeType === 1) {\r\n index++;\r\n }\r\n sibling = sibling.previousSibling;\r\n }\r\n path.unshift(index);\r\n node = node.parentNode;\r\n }\r\n\r\n // Hard fix - need to remove first element to work correctly\r\n path.shift();\r\n\r\n return path;\r\n}\r\n\r\n/**\r\n * Retrieve a DOM node from a path\r\n *\r\n * @param {int[]} path\r\n * @return {*|null}\r\n */\r\nfunction spotFixRetrieveNodeFromPath(path) {\r\n // @ToDo check if the path is correct\r\n if ( ! path ) {\r\n return null;\r\n }\r\n\r\n let node = document;\r\n for (let i = 0; i < path.length; i++) {\r\n node = node.children[path[i]];\r\n if ( ! node ) {\r\n return null;\r\n }\r\n }\r\n return node;\r\n}\r\n\n/**\r\n * Return bool if widget is closed in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetWidgetIsClosed() {\r\n return localStorage.getItem('spotfix_widget_is_closed') === '1';\r\n}\r\n\r\n/**\r\n * Return bool if widget closed state is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageWidgetCloseIsSet() {\r\n return localStorage.getItem('spotfix_widget_is_closed') !== null;\r\n}\r\n\r\n/**\r\n * Save widget closed state\r\n * @param visible\r\n */\r\nfunction storageSetWidgetIsClosed(visible) {\r\n localStorage.setItem('spotfix_widget_is_closed', visible ? '1' : '0');\r\n}\r\n\r\n/**\r\n * Return bool if user is defined in local storage\r\n * @returns {boolean}\r\n */\r\nfunction storageGetUserIsDefined() {\r\n return localStorage.getItem('spotfix_user_id') !== null;\r\n}\r\n\r\n/**\r\n * Save data for updates check\r\n * @param tasks\r\n */\r\nfunction storageSaveTasksUpdateData(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n\r\n tasks.forEach(task => {\r\n if (task.taskId && task.taskLastUpdate) {\r\n storedTasks[task.taskId] = {\r\n taskId: task.taskId,\r\n taskLastUpdate: task.taskLastUpdate\r\n };\r\n }\r\n });\r\n\r\n localStorage.setItem('spotfix_task_updates', JSON.stringify(storedTasks));\r\n}\r\n\r\nfunction storageSaveTasksCount(tasks) {\r\n if (!tasks || !Array.isArray(tasks)) {\r\n return;\r\n }\r\n\r\n const count = tasks.filter(task => {\r\n return task.taskMeta;\r\n })?.length;\r\n\r\n localStorage.setItem('spotfix_tasks_count', `${count}`);\r\n}\r\n\r\n/**\r\n * Check if a specific task has been updated since last check\r\n * @param taskId\r\n * @param currentLastUpdate\r\n * @returns {boolean|null}\r\n */\r\nfunction storageCheckTaskUpdate(taskId, currentLastUpdate) {\r\n if (!taskId || !currentLastUpdate) {\r\n return null;\r\n }\r\n\r\n let storedTasks = {};\r\n try {\r\n storedTasks = JSON.parse(localStorage.getItem('spotfix_task_updates') || '{}');\r\n } catch (error) {\r\n storedTasks = {};\r\n }\r\n const storedTask = storedTasks[taskId];\r\n\r\n if (!storedTask) {\r\n return false;\r\n }\r\n\r\n const storedUpdate = new Date(storedTask.taskLastUpdate);\r\n const currentUpdate = new Date(currentLastUpdate);\r\n return currentUpdate > storedUpdate;\r\n}\r\n\r\n/**\r\n * Add unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageAddUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n if (!storedUnread.includes(taskId)) {\r\n storedUnread.push(taskId);\r\n }\r\n\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Remove unread update for a specific task\r\n * @param taskId\r\n */\r\nfunction storageRemoveUnreadUpdateForTaskID(taskId) {\r\n if (!taskId) {\r\n return;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n storedUnread = storedUnread.filter(id => id !== taskId);\r\n localStorage.setItem('spotfix_unread_updates', JSON.stringify(storedUnread));\r\n}\r\n\r\n/**\r\n * Check if there are any unread updates\r\n * @returns {boolean}\r\n */\r\nfunction storageTasksHasUnreadUpdates() {\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.length > 0;\r\n}\r\n\r\n/**\r\n * Check if a specific task has unread updates\r\n * @param taskId\r\n * @returns {boolean}\r\n */\r\nfunction storageProvidedTaskHasUnreadUpdates(taskId) {\r\n if (!taskId) {\r\n return false;\r\n }\r\n\r\n let storedUnread = [];\r\n try {\r\n storedUnread = JSON.parse(localStorage.getItem('spotfix_unread_updates') || '[]');\r\n } catch (error) {\r\n storedUnread = [];\r\n }\r\n\r\n return storedUnread.includes(taskId.toString());\r\n}\r\n\r\nfunction storageSaveSpotfixVersion (version) {\r\n localStorage.setItem('spotfix_app_version', `${version}`);\r\n}\r\n\r\nfunction clearLocalstorageOnLogout () {\r\n localStorage.removeItem('spotfix_email');\r\n localStorage.removeItem('spotfix_session_id');\r\n localStorage.removeItem('spotfix_user_id');\r\n localStorage.setItem('spotfix_widget_is_closed', '1');\r\n}\r\n\n/**\r\n * File uploader handler for managing file attachments with validation and upload capabilities\r\n */\r\nclass FileUploader {\r\n /**\r\n * Create a new FileUploader instance\r\n * @param {function} escapeHtmlHandler - Function to escape HTML strings for security\r\n */\r\n constructor(escapeHtmlHandler) {\r\n /** @type {Array<{id: string, file: File}>} */\r\n this.files = [];\r\n\r\n /** @type {number} Maximum allowed file size in bytes */\r\n this.maxFileSize = 5 * 1024 * 1024; // 5MB\r\n\r\n /** @type {number} Maximum total size for all files in bytes */\r\n this.maxTotalSize = 25 * 1024 * 1024; // 25MB\r\n\r\n /** @type {number} Maximum number of files allowed */\r\n this.maxFiles = 5;\r\n\r\n /** @type {string[]} Allowed MIME types for files */\r\n this.allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'text/plain', 'application/msword'];\r\n\r\n /** @type {function} HTML escaping function for XSS protection */\r\n this.escapeHtmlHandler = escapeHtmlHandler;\r\n\r\n /** @type {string[]} File size units for display */\r\n this.SIZE_UNITS = ['Bytes', 'KB', 'MB', 'GB'];\r\n }\r\n\r\n /**\r\n * Initialize elements and bindings. Should be called only for comments.\r\n * @returns {void}\r\n */\r\n init() {\r\n this.initializeElements();\r\n this.bindFilesInputChange();\r\n }\r\n\r\n /**\r\n * Define widget elements to work with uploader.\r\n * @returns {void}\r\n */\r\n initializeElements() {\r\n /** @type {HTMLInputElement|null} */\r\n this.fileInput = document.getElementById('doboard_task_widget__file-upload__file-input-button');\r\n\r\n /** @type {HTMLElement|null} */\r\n this.fileList = document.getElementById('doboard_task_widget__file-upload__file-list');\r\n\r\n this.uploaderWrapper = document.getElementById('doboard_task_widget__file-upload__wrapper');\r\n\r\n /** @type {HTMLElement|null} */\r\n this.errorMessage = document.getElementById('doboard_task_widget__file-upload__error');\r\n\r\n if (!this.fileInput || !this.fileList || !this.errorMessage || this.uploaderWrapper) {\r\n console.warn('File uploader elements not found');\r\n }\r\n }\r\n\r\n /**\r\n * Define hidden file input change to run uploader logic.\r\n * @returns {void}\r\n */\r\n bindFilesInputChange() {\r\n if (this.fileInput) {\r\n this.fileInput.addEventListener('change', (e) => this.handleFileInputChange(e));\r\n }\r\n }\r\n\r\n /**\r\n * Bind action to paperclip button.\r\n * @param {HTMLElement} element - The paperclip button element\r\n * @returns {void}\r\n */\r\n bindPaperClipAction(element) {\r\n element.addEventListener('click', (e) => {\r\n e.preventDefault();\r\n if (this.fileInput) {\r\n this.fileInput.click();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Handle file input change event\r\n * @param {Event} event - File input change event\r\n * @returns {void}\r\n */\r\n handleFileInputChange(event) {\r\n this.clearError();\r\n\r\n const selectedFiles = Array.from(event.target.files);\r\n if (this.files.length + selectedFiles.length > this.maxFiles) {\r\n this.showError(`Maximum ${this.maxFiles} files can be attached.`);\r\n return;\r\n }\r\n const validFiles = selectedFiles.filter(file => this.validateFile(file));\r\n\r\n validFiles.forEach(file => this.addFile(file));\r\n\r\n // Reset input to allow selecting same files again\r\n event.target.value = '';\r\n\r\n // show wrapper\r\n this.uploaderWrapper.style.display = 'block';\r\n }\r\n\r\n /**\r\n * Validate a file against upload constraints\r\n * @param {File} file - File to validate\r\n * @returns {boolean} True if file is valid, false otherwise\r\n */\r\n validateFile(file) {\r\n // Check file size\r\n if (file.size > this.maxFileSize) {\r\n this.showError(`File \"${file.name}\" is too large. Maximum size: ${this.formatFileSize(this.maxFileSize)}`);\r\n return false;\r\n }\r\n\r\n // Check total size\r\n const totalSize = this.getTotalSize() + file.size;\r\n if (totalSize > this.maxTotalSize) {\r\n this.showError(`Total files size exceeded. Maximum: ${this.formatFileSize(this.maxTotalSize)}`);\r\n return false;\r\n }\r\n\r\n // Check file type\r\n if (this.allowedTypes.length > 0 && !this.allowedTypes.includes(file.type)) {\r\n this.showError(`File type \"${file.type}\" for \"${file.name}\" is not supported.`);\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Calculate total size of all files\r\n * @returns {number} Total size in bytes\r\n */\r\n getTotalSize() {\r\n return this.files.reduce((sum, fileData) => sum + fileData.file.size, 0);\r\n }\r\n\r\n /**\r\n * Add a file to the upload queue\r\n * @param {File} file - File to add\r\n * @returns {void}\r\n */\r\n addFile(file) {\r\n const fileWithId = {\r\n id: this.generateFileId(),\r\n file: file\r\n };\r\n\r\n this.files.push(fileWithId);\r\n this.renderFileList();\r\n }\r\n\r\n /**\r\n * Generate a unique file ID\r\n * @returns {string} Unique file identifier\r\n * @private\r\n */\r\n generateFileId() {\r\n return Date.now() + Math.random().toString(36).substr(2, 9);\r\n }\r\n\r\n /**\r\n * Remove a file from the upload queue\r\n * @param {string} fileId - ID of the file to remove\r\n * @returns {void}\r\n */\r\n removeFile(fileId) {\r\n this.files = this.files.filter(f => f.id !== fileId);\r\n this.renderFileList();\r\n this.clearError();\r\n }\r\n\r\n /**\r\n * Render the file list in the UI\r\n * @returns {void}\r\n */\r\n renderFileList() {\r\n if (!this.fileList) return;\r\n\r\n if (this.files.length === 0) {\r\n this.fileList.innerHTML = ksesFilter('
No files attached
');\r\n return;\r\n }\r\n\r\n const fileItems = this.files.map(fileData => this.createFileItem(fileData));\r\n this.fileList.innerHTML = ksesFilter('');\r\n fileItems.forEach(item => this.fileList.appendChild(item));\r\n }\r\n\r\n /**\r\n * Create file item element for display\r\n * @param {object} fileData - File data object\r\n * @param {string} fileData.id - File identifier\r\n * @param {File} fileData.file - File object\r\n * @returns {HTMLDivElement} File item DOM element\r\n */\r\n createFileItem(fileData) {\r\n const { file, id } = fileData;\r\n const fileItem = document.createElement('div');\r\n fileItem.className = 'doboard_task_widget__file-upload__file-item';\r\n\r\n fileItem.innerHTML = ksesFilter(`\r\n
\r\n
\r\n
${this.escapeHtmlHandler(String(file.name))}
\r\n
${this.formatFileSize(file.size)}
\r\n
\r\n
\r\n \r\n `);\r\n\r\n const removeBtn = fileItem.querySelector('.doboard_task_widget__file-upload__remove-btn');\r\n removeBtn.addEventListener('click', () => this.removeFile(id));\r\n\r\n return fileItem;\r\n }\r\n\r\n /**\r\n * Format file size for display\r\n * @param {number} bytes - File size in bytes\r\n * @returns {string} Formatted file size string\r\n */\r\n formatFileSize(bytes) {\r\n if (bytes === 0) return '0 Bytes';\r\n\r\n const k = 1024;\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n\r\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + this.SIZE_UNITS[i];\r\n }\r\n\r\n /**\r\n * Show uploader error message\r\n * @param {string} message - Error message to display\r\n * @returns {void}\r\n */\r\n showError(message) {\r\n if (this.errorMessage) {\r\n this.errorMessage.textContent = message;\r\n this.errorMessage.style.display = 'block';\r\n }\r\n }\r\n\r\n /**\r\n * Clear uploader error message\r\n * @returns {void}\r\n */\r\n clearError() {\r\n if (this.errorMessage) {\r\n this.errorMessage.textContent = '';\r\n this.errorMessage.style.display = 'none';\r\n }\r\n }\r\n\r\n /**\r\n * Check if there are files to send\r\n * @returns {boolean} True if files are present, false otherwise\r\n */\r\n hasFiles() {\r\n return this.files.length > 0;\r\n }\r\n\r\n /**\r\n * Clear all files from upload queue\r\n * @returns {void}\r\n */\r\n clearFiles() {\r\n this.files = [];\r\n this.renderFileList();\r\n }\r\n\r\n /**\r\n * Validate file data structure before upload\r\n * @param {object} fileData - File data object to validate\r\n * @param {string} fileData.sessionId - Session identifier\r\n * @param {object} fileData.params - Additional parameters\r\n * @param {string} fileData.params.accountId - Account identifier\r\n * @param {string} fileData.params.projectToken - Project token\r\n * @param {string} fileData.commentId - Comment identifier\r\n * @param {string} fileData.fileName - File name\r\n * @param {File} fileData.fileBinary - File binary data\r\n * @returns {object} Validated file data\r\n * @throws {Error} When file data validation fails\r\n */\r\n validateFileData(fileData) {\r\n const validations = [\r\n { field: 'sessionId', type: 'string', message: 'No valid session found.' },\r\n { field: 'params.accountId', type: 'string', message: 'No valid account ID found.' },\r\n { field: 'params.projectToken', type: 'string', message: 'No valid project token found.' },\r\n { field: 'commentId', type: 'string', message: 'No valid commentId found.' },\r\n { field: 'fileName', type: 'string', message: 'No valid filename found.' }\r\n ];\r\n\r\n for (const validation of validations) {\r\n const value = this.getNestedValue(fileData, validation.field);\r\n if (!value || typeof value !== validation.type) {\r\n throw new Error(validation.message);\r\n }\r\n }\r\n\r\n if (!fileData.fileBinary || !(fileData.fileBinary instanceof File)) {\r\n throw new Error('No valid file object found.');\r\n }\r\n\r\n return fileData;\r\n }\r\n\r\n /**\r\n * Helper to get nested object values\r\n * @param {object} obj - Object to traverse\r\n * @param {string} path - Dot notation path to value\r\n * @returns {*} Value at the specified path\r\n * @private\r\n */\r\n getNestedValue(obj, path) {\r\n return path.split('.').reduce((current, key) => current?.[key], obj);\r\n }\r\n\r\n /**\r\n * Send single file attachment\r\n * @param {object} fileData - File data for upload\r\n * @returns {Promise} Upload response\r\n */\r\n async sendSingleAttachment(fileData) {\r\n const validatedFileData = await this.validateFileData(fileData);\r\n return await attachmentAddDoboard(validatedFileData);\r\n }\r\n\r\n /**\r\n * Send all attachments for a comment\r\n * @param {object} params - Upload parameters\r\n * @param {string} sessionId - Session identifier\r\n * @param {string} commentId - Comment identifier\r\n * @returns {Promise} Upload results\r\n */\r\n async sendAttachmentsForComment(params, sessionId, commentId) {\r\n /** @type {object} */\r\n const results = {\r\n preparedFilesCount: this.files.length,\r\n sentFilesCount: 0,\r\n fileResults: [],\r\n success: true\r\n };\r\n\r\n for (let i = 0; i < this.files.length; i++) {\r\n const fileData = this.files[i];\r\n /** @type {object} */\r\n const result = {\r\n success: false,\r\n response: null,\r\n error: null\r\n };\r\n\r\n try {\r\n const attachmentData = {\r\n params,\r\n sessionId,\r\n commentId,\r\n fileName: fileData.file.name,\r\n fileBinary: fileData.file,\r\n attachmentOrder: i\r\n };\r\n\r\n const response = await this.sendSingleAttachment(attachmentData);\r\n result.response = response;\r\n result.success = response.status === 200;\r\n\r\n if (result.success) {\r\n results.sentFilesCount++;\r\n }\r\n } catch (error) {\r\n result.error = error.message;\r\n }\r\n\r\n results.fileResults.push(result);\r\n }\r\n\r\n results.success = results.preparedFilesCount === results.sentFilesCount;\r\n this.clearFiles();\r\n\r\n return results;\r\n }\r\n}\r\n\nclass SpotFixTemplatesLoader {\r\n static getTemplateCode(templateName) {\r\n const templateMethod = this[templateName];\r\n\r\n if (typeof templateMethod !== 'function') {\r\n throw new Error(`Template method '${templateName}' not found`);\r\n }\r\n\r\n let template = templateMethod.call(this).trim();\r\n\r\n return template;\r\n }\r\n\r\n static all_issues() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n All spots \r\n
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n
`;\r\n }\r\n\r\n static concrete_issue() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n All {{issuesCounter}}\r\n
\r\n
{{issueTitle}}
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n \r\n
\r\n \r\n \r\n
\r\n
\r\n
Attached files
\r\n
\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static concrete_issue_day_content() {\r\n return `\r\n
\r\n
{{dayContentMonthDay}}
\r\n
{{dayContentMessages}}
\r\n {{statusFixedHtml}}\r\n
\r\n`;\r\n }\r\n\r\n static concrete_issue_messages() {\r\n return `\r\n
\r\n
\r\n {{taskAuthorInitials}}\r\n
\r\n
\r\n
{{commentBody}}
\r\n
{{commentTime}}
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static create_issue() {\r\n return `\r\n
\r\n
\r\n
\r\n \"\"\r\n Report an issue\r\n
\r\n
\r\n \r\n \"\"\r\n \r\n \r\n \"\"\r\n \r\n \"\"\r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n Tell us about any issue you’re experiencing on {{currentDomain}}. \r\n You’re also welcome to review spelling, grammar, or ask a question related to this page.\r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n\r\n If you want to receive notifications by email write here you email contacts.\r\n\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n Note about DoBoard register and accepting email notifications about tasks have to be here.\r\n\r\n
\r\n\r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static list_issues() {\r\n return `\r\n
\r\n
\r\n {{taskAuthorInitials}}\r\n
\r\n
\r\n
\r\n
\r\n {{taskTitle}}\r\n
\r\n \"\"\r\n
\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n {{statusFixedHtml}}\r\n
\r\n
\r\n
\r\n`;\r\n }\r\n\r\n static user_menu() {\r\n return `\r\n
\r\n
\r\n
\r\n
\r\n \"\"\r\n Back\r\n
\r\n
\r\n \"\"\r\n
\r\n
\r\n
\r\n \"\"\r\n {{userName}}\r\n {{email}}\r\n \r\n Sign up or Log in\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \"\"\r\n
\r\n \r\n \r\n Show widget on my screen\r\n \r\n The widget will be visible again if you select any text on the site\r\n \r\n \r\n
\r\n
\r\n
\r\n \r\n \"\"\r\n Log out\r\n \r\n
\r\n
\r\n
\r\n
\r\n {{spotfixVersion}}\r\n Powered by\r\n \r\n doBoard\r\n \r\n
\r\n
\r\n
`;\r\n }\r\n\r\n static wrap() {\r\n return `\r\n
\r\n\r\n\r\n
\r\n
`;\r\n }\r\n\r\n static wrap_review() {\r\n return `\r\n`;\r\n }\r\n\r\n static fixedHtml() {\r\n return `

Finished

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

This issue already fixed

`;\r\n }\r\n\r\n}\r\n\nclass SpotFixSVGLoader {\r\n static loadSVG(svgName) {\r\n const svgMethod = this[svgName];\r\n\r\n if (typeof svgMethod !== 'function') {\r\n throw new Error(`Template method '${svgName}' not found`);\r\n }\r\n\r\n return svgMethod.call(this).trim();\r\n }\r\n\r\n static getAsRawSVG(svgName) {\r\n return this.loadSVG(svgName);\r\n }\r\n\r\n static getAsDataURI(svgName) {\r\n const svg = this.loadSVG(svgName);\r\n return this.svgToDataURI(svg);\r\n }\r\n\r\n static svgToDataURI(svgString) {\r\n const bytes = new TextEncoder().encode(svgString);\r\n const baseBtoa = btoa(String.fromCharCode(...bytes));\r\n return `data:image/svg+xml;base64,${baseBtoa}`;\r\n }\r\n\r\n static chevronBack() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static chevronBackDark() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static buttonCloseScreen() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static buttonSendMessage() {\r\n return `\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n`;\r\n }\r\n\r\n static buttonPaperClip() {\r\n return `\r\n\r\n \r\n`;\r\n }\r\n\r\n static logoDoBoardGreen() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static logoDoBoardWrap() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotPublic() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotPrivate() {\r\n return `\r\n\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconSpotWidgetWrapPencil() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconLinkChain() {\r\n return `\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconEllipsesMore() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconAvatar() {\r\n return `\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n`;\r\n }\r\n\r\n static iconEye() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconDoor() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconPlus() {\r\n return `\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconMaximize() {\r\n return `\r\n\r\n\r\n\r\n\r\n\r\n`;\r\n }\r\n\r\n static iconMarker() {\r\n return ``;\r\n }\r\n}\r\n\nclass SpotFixSourcesLoader {\r\n\r\n constructor() {\r\n this.loadAll();\r\n }\r\n\r\n getCSSCode() {\r\n // global gulp wrapper var\r\n return spotFixCSS;\r\n }\r\n\r\n loadAll() {\r\n this.loadFonts();\r\n this.loadCSS();\r\n };\r\n\r\n loadFonts() {\r\n const preconnect_first = document.createElement('link');\r\n preconnect_first.rel = 'preconnect';\r\n preconnect_first.href = 'https://fonts.googleapis.com';\r\n document.head.appendChild(preconnect_first);\r\n\r\n const preconnect_second = document.createElement('link');\r\n preconnect_second.rel = 'preconnect';\r\n preconnect_second.href = 'https://fonts.gstatic.com';\r\n preconnect_second.crossOrigin = 'crossorigin';\r\n document.head.appendChild(preconnect_second);\r\n\r\n const fontLink = document.createElement('link');\r\n fontLink.rel = 'stylesheet';\r\n fontLink.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap';\r\n document.head.appendChild(fontLink);\r\n }\r\n\r\n loadCSS() {\r\n const style = document.createElement('style');\r\n style.setAttribute('id', 'spotfix_css');\r\n style.textContent = this.getCSSCode();\r\n document.head.appendChild(style);\r\n }\r\n}\r\n\ndocument.dispatchEvent(new CustomEvent('spotFixLoaded', {\r\n detail: {\r\n timestamp: new Date().toISOString(),\r\n message: 'All scripts loaded successfully'\r\n }\r\n}));\r\n"],"names":["DOBOARD_API_URL","spotfixApiCall","async","data","method","accountId","undefined","Error","key","formData","FormData","hasOwnProperty","append","let","endpointUrl","URL","error","response","await","fetch","body","networkError","message","responseBody","json","parseError","operation_status","errorMessage","operation_message","userConfirmEmailDoboard","emailConfirmationToken","email_confirmation_token","encodeURIComponent","result","sessionId","session_id","userId","user_id","email","accounts","operationStatus","createTaskDoboard","taskDetails","project_token","projectToken","project_id","projectId","localStorage","getItem","name","taskTitle","comment","taskDescription","meta","taskMeta","task_type","taskId","task_id","createTaskCommentDoboard","status","commentId","comment_id","attachmentAddDoboard","fileData","params","account_id","filename","fileName","file","fileBinary","attachment_order","attachmentOrder","registerUserDoboard","nickname","pageURL","confirmation_url","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","spotFixCSS","SPOTFIX_SELECTION_TYPE_TEXT","SPOTFIX_SELECTION_TYPE_IMG","SPOTFIX_SELECTION_TYPE_ELEMENT","spotFixGetSelectionType","range","getRangeAt","commonAncestor","commonAncestorContainer","spotFixGetSelectedImage","startContainer","endContainer","hasTextContent","isTextNode","TEXT_NODE","isCollapsed","collapsed","rangeCount","selectionType","startSelectPosition","endSelectPosition","commonNode","commonNodeElement","startOffset","endOffset","spotFixCalculateNodePath","imgElement","selectedImage","from","children","indexOf","imageUrl","widgetInstance","elementsMap","Map","spot","spotFixIsValidNodePath","spotFixRetrieveNodeFromPath","has","set","spots","spotFixHighlightImageElement","spotFixHighlightNestedElement","spotFixHighlightTextInElement","tooltipTitleText","spotfixHighlightOpen","text","spotSelectedText","markers","startPos","parseInt","endPos","slice","marker","insertText","idClass","cls","path","scrollIntoView","block","spans","affectedParents","Set","elementSelectionClassName","parent","tooltip","firstChild","removeChild","normalize","imageSelectionClassName","every","index","isInteger","imgNode","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","spotFixIsElementInRange","FILTER_ACCEPT","FILTER_REJECT","nextNode","startElement","spotFixGetElementFromNode","endElement","spotFixIsElementPartiallySelected","spotFixFindNearbyElements","elementRange","createRange","selectNode","compareBoundaryPoints","Range","START_TO_START","END_TO_END","elementRect","rangeRect","right","left","elements","previousElement","previousElementSibling","nextElement","nextElementSibling","sibling","previousSibling","unshift","shift","visible","storedTasks","count","currentLastUpdate","storedTask","storedUnread","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: '',\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 || '';\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/styles/doboard-widget.css b/styles/doboard-widget.css index 46da394..892f66e 100644 --- a/styles/doboard-widget.css +++ b/styles/doboard-widget.css @@ -252,14 +252,6 @@ line-height: 22px; } -/*** We still find no way to keep inlined SVG. ***/ -/*#doboard_task_widget-task_count:hover {*/ -/* background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHZpZXdCb3g9IjAgMCAyMiAyMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxmb3JlaWduT2JqZWN0IHg9Ii00IiB5PSItNCIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIj48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iYmFja2Ryb3AtZmlsdGVyOmJsdXIoMnB4KTtjbGlwLXBhdGg6dXJsKCNiZ2JsdXJfMF8xODk4OV8yODI2X2NsaXBfcGF0aCk7aGVpZ2h0OjEwMCU7d2lkdGg6MTAwJSI+PC9kaXY+PC9mb3JlaWduT2JqZWN0PjxwYXRoIGRhdGEtZmlnbWEtYmctYmx1ci1yYWRpdXM9IjQiIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjciLz4KICAgIDxwYXRoIGQ9Ik0xNiA2TDYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxwYXRoIGQ9Ik02IDZMMTYgMTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KICAgIDxkZWZzPgogICAgICAgIDxjbGlwUGF0aCBpZD0iYmdibHVyXzBfMTg5ODlfMjgyNl9jbGlwX3BhdGgiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgNCkiPjxwYXRoIGQ9Ik0xMSAyMkMxNy4wNzUxIDIyIDIyIDE3LjA3NTEgMjIgMTFDMjIgNC45MjQ4NyAxNy4wNzUxIDAgMTEgMEM0LjkyNDg3IDAgMCA0LjkyNDg3IDAgMTFDMCAxNy4wNzUxIDQuOTI0ODcgMjIgMTEgMjJaIi8+CiAgICAgICAgPC9jbGlwUGF0aD48L2RlZnM+Cjwvc3ZnPg==) no-repeat center;*/ -/* cursor: pointer;*/ -/* overflow: hidden;*/ -/* font-size: 0;*/ -/*}*/ - #doboard_task_widget-task_count.hidden { width: 0; height: 0; @@ -1164,11 +1156,6 @@ padding-bottom: 8px; } -/*.doboard_task_widget_tasks_list a {*/ -/* color: #40484F !important;*/ -/* text-decoration: none !important;*/ -/*}*/ - #doboard_task_widget-user_menu-logout_button { display: inline-flex; align-items: center; From b8bb5b8c70bc1e3bd44214d7b902ed704d43c755 Mon Sep 17 00:00:00 2001 From: Veronika Tseleva Date: Sat, 27 Dec 2025 21:16:04 +0400 Subject: [PATCH 20/20] Fix. Fix email field --- dist/doboard-widget-bundle.js | 4 ++-- dist/doboard-widget-bundle.min.js | 2 +- dist/doboard-widget-bundle.min.js.map | 2 +- js/src/widget.js | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dist/doboard-widget-bundle.js b/dist/doboard-widget-bundle.js index 6738f3b..7c3c2c0 100644 --- a/dist/doboard-widget-bundle.js +++ b/dist/doboard-widget-bundle.js @@ -960,7 +960,7 @@ class CleanTalkWidgetDoboard { chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'), buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), userName: 'Guest', - email: '', + email: localStorage.getItem('spotfix_email') || '', ...this.srcVariables}; break; case 'concrete_issue': @@ -1160,7 +1160,7 @@ class CleanTalkWidgetDoboard { if(user){ templateVariables.userName = user.name || 'Guest'; - templateVariables.email = user.email || ''; + templateVariables.email = user.email || localStorage.getItem('spotfix_email') || ''; if(user?.avatar?.s) templateVariables.avatar = user?.avatar?.s; } diff --git a/dist/doboard-widget-bundle.min.js b/dist/doboard-widget-bundle.min.js index 5a14db2..32e44b0 100644 --- a/dist/doboard-widget-bundle.min.js +++ b/dist/doboard-widget-bundle.min.js @@ -1,4 +1,4 @@ -let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&clearLocalstorageOnLogout()},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e&&(e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)}))}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button")?.closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:window.location.href})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{logoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
+let DOBOARD_API_URL="https://api.doboard.com",spotfixApiCall=async(e,t,a=void 0)=>{if(!e||"object"!=typeof e)throw new Error("Data must be a valid object");if(!t||"string"!=typeof t)throw new Error("Method must be a valid string");if(void 0!==a&&"string"!=typeof a&&"number"!=typeof a)throw new Error("AccountId must be a string or number");var i,o=new FormData;for(i in e)e.hasOwnProperty(i)&&null!=e[i]&&o.append(i,e[i]);let s;s=void 0!==a?DOBOARD_API_URL+`/${a}/`+t:DOBOARD_API_URL+"/"+t;try{new URL(s)}catch(e){throw new Error("Invalid endpoint URL: "+s)}let r;try{r=await fetch(s,{method:"POST",body:o})}catch(e){throw new Error("Network error: "+e.message)}let d;try{d=await r.json()}catch(e){throw new Error("Failed to parse JSON response from server")}if(!d||"object"!=typeof d)throw new Error("Invalid response format from server");if(!d.data)throw new Error("Missing data field in server response");if(!d.data.operation_status)throw new Error("Missing operation_status in response data");if("FAILED"===d.data.operation_status)throw a=d.data.operation_message||"Operation failed without specific message",new Error(a);if("SUCCESS"===d.data.operation_status)return d.data;throw new Error("Unknown operation status: "+d.data.operation_status)},userConfirmEmailDoboard=async e=>{e={email_confirmation_token:encodeURIComponent(e)},e=await spotfixApiCall(e,"user_confirm_email");return{sessionId:e.session_id,userId:e.user_id,email:e.email,accounts:e.accounts,operationStatus:e.operation_status}},createTaskDoboard=async(e,t)=>{var a=t.accountId,e={session_id:e,project_token:t.projectToken,project_id:t.projectId,user_id:localStorage.getItem("spotfix_user_id"),name:t.taskTitle,comment:t.taskDescription,meta:t.taskMeta,task_type:"PUBLIC"};return{taskId:(await spotfixApiCall(e,"task_add",a)).task_id}},createTaskCommentDoboard=async(e,t,a,i,o,s="ACTIVE")=>{t={session_id:t,project_token:o,task_id:a,comment:i,status:s};return{commentId:(await spotfixApiCall(t,"comment_add",e)).comment_id}},attachmentAddDoboard=async e=>{var t=e.params.accountId,e={session_id:e.sessionId,project_token:e.params.projectToken,account_id:e.params.accountId,comment_id:e.commentId,filename:e.fileName,file:e.fileBinary,attachment_order:e.attachmentOrder};await spotfixApiCall(e,"attachment_add",t)},registerUserDoboard=async(e,t,a,i,o)=>{e={project_token:e,account_id:t,confirmation_url:a},a&&i&&(e.email=a,e.name=i),t=await spotfixApiCall(e,"user_registration");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},loginUserDoboard=async(e,t)=>{e={email:e,password:t},t=await spotfixApiCall(e,"user_authorize");return{sessionId:t.session_id,userId:t.user_id,email:t.email,accountExists:1===t.user_email_confirmed,operationMessage:t.operation_message,operationStatus:t.operation_status,userEmailConfirmed:t.user_email_confirmed}},logoutUserDoboard=async e=>{var t=localStorage.getItem("spotfix_session_id");t&&e&&(t={session_id:t},"SUCCESS"===(await spotfixApiCall(t,"user_unauthorize",e)).operation_status)&&clearLocalstorageOnLogout()},getTasksDoboard=async(e,t,a,i,o)=>{t={session_id:t,project_token:e,project_id:i,task_type:"PUBLIC"};o&&(t.user_id=o);e=(await spotfixApiCall(t,"task_get",a)).tasks.map(e=>({taskId:e.task_id,taskTitle:e.name,taskLastUpdate:e.updated,taskCreated:e.created,taskCreatorTaskUser:e.creator_user_id,taskMeta:e.meta,taskStatus:e.status}));return storageSaveTasksCount(e),e},getTasksCommentsDoboard=async(e,t,a,i="ACTIVE")=>{e={session_id:e,project_token:a,status:i};return(await spotfixApiCall(e,"comment_get",t)).comments.map(e=>({taskId:e.task_id,commentId:e.comment_id,userId:e.user_id,commentBody:e.comment,commentDate:e.updated,status:e.status,issueTitle:e.task_name}))},getUserDoboard=async(e,t,a,i)=>{e={session_id:e,project_token:t},i&&(e.user_id=i),t=await spotfixApiCall(e,"user_get",a);return t.users},userUpdateDoboard=async(e,t,a,i,o)=>{a={session_id:a,project_token:e,user_id:i,timestamp:o};return await spotfixApiCall(a,"user_update",t),{success:!0}},getReleaseVersion=async()=>{try{var e=await(await fetch("https://api.github.com/repos/CleanTalk/SpotFix/releases")).json();return 0+e.taskId==+a)?.taskStatus}}async function getUserDetails(e){var t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_user_id");if(a)return(await getUserDoboard(t,e.projectToken,e.accountId,a))[0]||{}}async function handleCreateTask(e,t){try{var a,i=await createTaskDoboard(e,t);return i&&i.taskId&&t.taskDescription&&(a=`


The spot has been posted at the following URL ${window.location.href}`,await addTaskComment({projectToken:t.projectToken,accountId:t.accountId},i.taskId,t.taskDescription+a)),i}catch(e){throw e}}async function addTaskComment(e,t,a){var i=localStorage.getItem("spotfix_session_id");if(!i)throw new Error("No session");if(e.projectToken&&e.accountId)return createTaskCommentDoboard(e.accountId,i,t,a,e.projectToken);throw new Error("Missing params")}function getUserTasks(e){var t,a,i;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),getTasksDoboard(t,a,e.accountId,e.projectId,i)):{}}async function getAllTasks(e){var t,a;return localStorage.getItem("spotfix_session_id")?(t=e.projectToken,a=localStorage.getItem("spotfix_session_id"),(await getTasksDoboard(t,a,e.accountId,e.projectId)).filter(e=>e.taskMeta)):{}}function formatDate(e){if(!e)return{date:"",time:""};let t;return t=!e.includes("T")&&e.includes(" ")?new Date(e.replace(" ","T")):new Date(e),isNaN(t.getTime())?{date:"",time:""}:(e=t.getTimezoneOffset(),{date:["January","February","March","April","May","June","July","August","September","October","November","December"][(e=new Date(t.getTime()-6e4*e)).getMonth()]+" "+e.getDate(),time:e.getHours().toString().padStart(2,"0")+":"+e.getMinutes().toString().padStart(2,"0")})}function getTaskAuthorDetails(e,t){localStorage.getItem("spotfix_session_id");var a=[{taskId:"1",taskAuthorAvatarImgSrc:"https://s3.eu-central-1.amazonaws.com/cleantalk-ctask-atts/accounts/1/avatars/081a1b65d20fe318/m.jpg",taskAuthorName:"Test All Issues Single Author Name"}].find(e=>e.taskId===t);return void 0===a?{taskId:null,taskAuthorAvatarImgSrc:null,taskAuthorName:"Task Author"}:a}function getIssuesCounterString(e,t){return` (${e}/${t})`}function getAvatarSrc(e){if(e&&e.avatar){if("object"==typeof e.avatar&&e.avatar.m)return e.avatar.m;if("string"==typeof e.avatar)return e.avatar}return null}function getAuthorName(e){if(e){if(e.name&&0registerUserDoboard(o,s,a,i,r).then(e=>{if(e.accountExists)document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container").innerText=ksesFilter("Account already exists. Please, login usin your password."),document.querySelector(".doboard_task_widget-accordion>.doboard_task_widget-input-container.hidden").classList.remove("hidden"),document.getElementById("doboard_task_widget-user_password").focus();else if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email),userUpdate(o,s);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function loginUser(e){let a=e.userEmail,i=e.userPassword;return t=>loginUserDoboard(a,i).then(e=>{if(e.sessionId)localStorage.setItem("spotfix_session_id",e.sessionId),localStorage.setItem("spotfix_user_id",e.userId),localStorage.setItem("spotfix_email",e.email);else{if(!("SUCCESS"===e.operationStatus&&e.operationMessage&&0{throw e})}function userUpdate(e,t){var a=localStorage.getItem("spotfix_session_id"),i=localStorage.getItem("spotfix_user_id"),o=Intl.DateTimeFormat().resolvedOptions().timeZone;return userUpdateDoboard(e,t,a,i,o)}function spotFixSplitUrl(e){try{var t,a,i,o;return e&&""!==e.trim()?(a=(t=new URL(e)).host,0===(i=t.pathname.split("/").filter(Boolean)).length?a:((o=i.reverse()).push(a),o.join(" / "))):""}catch(e){return""}}function setToggleStatus(t){var e=document.getElementById("widget_visibility");e&&(e.checked=!0,e.addEventListener("click",()=>{let e=setTimeout(()=>{localStorage.setItem("spotfix_widget_is_closed","1"),t.hide(),clearTimeout(e)},300)}))}function checkLogInOutButtonsVisible(){var e;localStorage.getItem("spotfix_session_id")?(e=document.getElementById("doboard_task_widget-user_menu-signlog_button"))&&(e.style.display="none"):(e=document.getElementById("doboard_task_widget-user_menu-logout_button")?.closest(".doboard_task_widget-user_menu-item"))&&(e.style.display="none")}function changeSize(e){e&&+localStorage.getItem("maximize")?e.classList.add("doboard_task_widget-container-maximize"):e&&e.classList.remove("doboard_task_widget-container-maximize")}class CleanTalkWidgetDoboard{selectedText="";selectedData={};widgetElement=null;params={};currentActiveTaskId=0;savedIssuesQuantityOnPage=0;savedIssuesQuantityAll=0;allTasksData={};srcVariables={};constructor(e,t){this.selectedData=e||"",this.selectedText=e?.selectedText||"",this.init(t),this.srcVariables={buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),iconPlus:SpotFixSVGLoader.getAsDataURI("iconPlus"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),chevronBack:SpotFixSVGLoader.getAsDataURI("chevronBack"),buttonPaperClip:SpotFixSVGLoader.getAsDataURI("buttonPaperClip"),buttonSendMessage:SpotFixSVGLoader.getAsDataURI("buttonSendMessage"),logoDoBoardGreen:SpotFixSVGLoader.getAsDataURI("logoDoBoardGreen"),logoDoBoardWrap:SpotFixSVGLoader.getAsDataURI("logoDoBoardWrap"),iconSpotWidgetWrapPencil:SpotFixSVGLoader.getAsDataURI("iconSpotWidgetWrapPencil"),iconMarker:SpotFixSVGLoader.getAsDataURI("iconMarker"),iconSpotPublic:SpotFixSVGLoader.getAsDataURI("iconSpotPublic"),iconSpotPrivate:SpotFixSVGLoader.getAsDataURI("iconSpotPrivate"),iconLinkChain:SpotFixSVGLoader.getAsDataURI("iconLinkChain")},this.fileUploader=new FileUploader(this.escapeHtml)}async init(e){this.params=this.getParams();var t=new URLSearchParams(window.location.search),a=t.get("email_confirmation_token");if(a)try{var i=await confirmUserEmail(a,this.params),o=(this.allTasksData=await getAllTasks(this.params),this.currentActiveTaskId=i.taskId,storageSetWidgetIsClosed(!(e="concrete_issue")),t.delete("email_confirmation_token"),window.location.pathname+(t.toString()?"?"+t.toString():""));window.history.replaceState({},document.title,o)}catch(e){this.registrationShowMessage("Error confirming email: "+e.message,"error")}else{a=localStorage.getItem("spotfix_widget_is_closed");(!a||this.selectedText)&&a||(this.allTasksData=await getAllTasks(this.params))}let s;storageTasksHasUnreadUpdates()?s=!0:"wrap_review"===e&&(s=await checkIfTasksHasSiteOwnerUpdates(this.allTasksData,this.params)),storageSaveTasksUpdateData(this.allTasksData),storageWidgetCloseIsSet()||storageSetWidgetIsClosed(!0),s&&storageSetWidgetIsClosed(!1),this.widgetElement=await this.createWidgetElement(e),this.bindWidgetInputsInteractive()}getParams(){var e=document.querySelector('script[src*="doboard-widget-bundle."]');if(!e||!e.src)throw new Error("Script not provided");e=new URL(e.src),e=Object.fromEntries(e.searchParams.entries());if(!e)throw new Error("Script params not provided");if(e.projectToken&&e.accountId&&e.projectId)return e;throw new Error("Necessary script params not provided")}bindCreateTaskEvents(){var e=document.getElementById("doboard_task_widget-submit_button");e&&e.addEventListener("click",async()=>{var e=document.getElementById("doboard_task_widget-title"),s=e.value;if(s){var t=document.getElementById("doboard_task_widget-description"),r=t.value;if(r){let t="",a="",i="";var d=document.querySelector(".doboard_task_widget-login");if(d&&d.classList.contains("active")){let e=document.getElementById("doboard_task_widget-user_email");var d=document.getElementById("doboard_task_widget-user_name"),n=document.getElementById("doboard_task_widget-user_password");if(!(a=e.value))return e.style.borderColor="red",e.focus(),void e.addEventListener("input",function(){this.style.borderColor=""});if(e&&d&&!(t=d.value))return d.style.borderColor="red",d.focus(),void d.addEventListener("input",function(){this.style.borderColor=""});if(e&&n&&!d&&!(i=n.value))return n.style.borderColor="red",n.focus(),void n.addEventListener("input",function(){this.style.borderColor=""})}let e=document.getElementById("doboard_task_widget-user_email");a=e.value;d=document.getElementById("doboard_task_widget-submit_button"),n=(d.disabled=!0,d.innerText=ksesFilter("Creating spot..."),{taskTitle:s,taskDescription:r,selectedData:this.selectedData,projectToken:this.params.projectToken,projectId:this.params.projectId,accountId:this.params.accountId,taskMeta:JSON.stringify(this.selectedData||{pageURL:window.location.href})});a&&(n.userEmail=a),t&&(n.userName=t),i&&(n.userPassword=i),localStorage.setItem("spotfix_pending_task",JSON.stringify({...this.selectedData,description:r}));let o;try{o=await this.submitTask(n)}catch(e){return void this.registrationShowMessage(e.message)}d.disabled=!1,d.style.cursor="pointer",o.needToLogin||(void 0!==o.isPublic&&(this.selectedData.isPublic=o.isPublic),this.allTasksData=await getAllTasks(this.params),storageSaveTasksUpdateData(this.allTasksData),this.selectedData={},await this.createWidgetElement("all_issues"),storageSetWidgetIsClosed(!1),hideContainersSpinner(!1))}else t.style.borderColor="red",t.focus(),t.addEventListener("input",function(){this.style.borderColor=""})}else e.style.borderColor="red",e.focus(),e.addEventListener("input",function(){this.style.borderColor=""})})}async createWidgetElement(e,r=!1){var d=document.querySelector(".doboard_task_widget")?document.querySelector(".doboard_task_widget"):document.createElement("div");d.className="doboard_task_widget",d.innerHTML=ksesFilter(""),d.removeAttribute("style");let t="",n,l={};var a=window.SpotfixWidgetConfig,i={compact:"0vh",short:"20vh",regular:"45vh",tall:"60vh",extra:"85vh"};switch(e){case"create_issue":t="create_issue",this.type_name=t,l={selectedText:this.selectedText,currentDomain:document.location.hostname||"",buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),iconMaximize:SpotFixSVGLoader.getAsDataURI("iconMaximize"),iconEllipsesMore:SpotFixSVGLoader.getAsDataURI("iconEllipsesMore"),...this.srcVariables},storageGetUserIsDefined()&&storageSetWidgetIsClosed(!1);break;case"wrap":if(storageGetWidgetIsClosed())return;t="wrap",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"wrap_review":t="wrap_review",l={position:i[a?.verticalPosition]||i.compact,...this.srcVariables};break;case"all_issues":t="all_issues",this.type_name=t,l={...this.srcVariables};break;case"user_menu":t="user_menu";var o=localStorage.getItem("spotfix_app_version");l={spotfixVersion:o?"Spotfix version "+o+".":"",avatar:SpotFixSVGLoader.getAsDataURI("iconAvatar"),iconEye:SpotFixSVGLoader.getAsDataURI("iconEye"),iconDoor:SpotFixSVGLoader.getAsDataURI("iconDoor"),chevronBackDark:SpotFixSVGLoader.getAsDataURI("chevronBackDark"),buttonCloseScreen:SpotFixSVGLoader.getAsDataURI("buttonCloseScreen"),userName:"Guest",email:localStorage.getItem("spotfix_email")||"",...this.srcVariables};break;case"concrete_issue":t="concrete_issue",this.type_name=t,this.savedIssuesQuantityAll=Array.isArray(this.allTasksData)?this.allTasksData.length:0,this.savedIssuesQuantityOnPage=Array.isArray(this.allTasksData)?this.allTasksData.filter(e=>{try{return(e.taskMeta?JSON.parse(e.taskMeta):{}).pageURL===window.location.href}catch(e){return!1}}).length:0,l={issueTitle:"...",issueComments:[],issuesCounter:getIssuesCounterString(this.savedIssuesQuantityOnPage,this.savedIssuesQuantityAll),...this.srcVariables}}d.innerHTML=this.loadTemplate(t,l),document.body.appendChild(d),spotFixRemoveHighlights();var c=document.querySelector(".doboard_task_widget-container");switch(e){case"create_issue":c&&+localStorage.getItem("maximize")?c.classList.add("doboard_task_widget-container-maximize"):c&&c.classList.remove("doboard_task_widget-container-maximize");var g=window.getSelection(),p=!!localStorage.getItem("spotfix_session_id"),u=localStorage.getItem("spotfix_email");p&&u&&!u.includes("spotfix_")&&document.querySelector(".doboard_task_widget-login").classList.add("hidden"),"Range"===g.type&&(spotFixScrollToNodePath(spotFixGetSelectedData(g).nodePath),this.positionWidgetContainer()),this.bindCreateTaskEvents();break;case"wrap":await this.getTaskCount(),document.querySelector(".doboard_task_widget-wrap").addEventListener("click",e=>{e=e.currentTarget.classList;e&&!e.contains("hidden")&&this.createWidgetElement("all_issues")}),hideContainersSpinner(!1);break;case"wrap_review":document.querySelector("#doboard_task_widget_button").addEventListener("click",e=>{spotFixOpenWidget(this.selectedData,"create_issue")});break;case"all_issues":changeSize(c),spotFixRemoveHighlights();let o=0;this.allTasksData?.length||(this.allTasksData=await getAllTasks(this.params));var p=this.allTasksData,_=(n=await getTasksFullDetails(this.params,p,this.currentActiveTaskId),[]);if(0{e=JSON.parse(e.taskMeta).pageURL===a?1:0;return(JSON.parse(t.taskMeta).pageURL===a?1:0)-e});document.querySelector(".doboard_task_widget-all_issues-container").innerHTML="";for(let i=0;iThe issues list is empty
')),this.bindIssuesClick(),hideContainersSpinner(!1);break;case"user_menu":setToggleStatus(this),checkLogInOutButtonsVisible();u=await getUserDetails(this.params),g=await getReleaseVersion(),p=localStorage.getItem("spotfix_app_version")||g;l.spotfixVersion=(p?`Spotfix version ${p}.`:"")||"",u&&(l.userName=u.name||"Guest",l.email=u.email||localStorage.getItem("spotfix_email")||"",u?.avatar?.s)&&(l.avatar=u?.avatar?.s),d.innerHTML=this.loadTemplate("user_menu",l),document.body.appendChild(d),setToggleStatus(this),checkLogInOutButtonsVisible();break;case"concrete_issue":changeSize(c);let a=await getTaskFullDetails(n=await getTasksFullDetails(this.params,this.allTasksData,this.currentActiveTaskId),this.currentActiveTaskId);g=document.querySelector(".doboard_task_widget-issue-title");g&&(g.innerText=ksesFilter(a.issueTitle)),l.issueTitle=a?.issueTitle,l.issueComments=a?.issueComments;let t=null;p=this.allTasksData.find(e=>String(e.taskId)===String(a.taskId));let i=null;if(p&&p.taskMeta)try{i=JSON.parse(p.taskMeta),t=i.nodePath||null}catch(e){t=null,i=null}l.taskPageUrl=i.pageURL;var u=i.pageURL.replace(window.location.origin,""),g=(l.taskFormattedPageUrl=u.length<2?i.pageURL.replace(window.location.protocol+"/",""):u,l.contenerClasess=+localStorage.getItem("maximize")?"doboard_task_widget-container-maximize doboard_task_widget-container":"doboard_task_widget-container",d.innerHTML=this.loadTemplate("concrete_issue",l),document.body.appendChild(d),spotFixRemoveHighlights(),i&&t&&(spotFixHighlightElements([i],this),"function"==typeof spotFixScrollToNodePath)&&spotFixScrollToNodePath(t),document.querySelector(".doboard_task_widget-concrete_issues-container")),v=[],I=localStorage.getItem("spotfix_user_id");if(0e.commentTime.localeCompare(t.commentTime)),E){var D=E[T];e+=this.loadTemplate("concrete_issue_messages",D)}t+=this.loadTemplate("concrete_issue_day_content",{dayContentMonthDay:S,dayContentMessages:e,statusFixedHtml:"DONE"!==n?.taskStatus?"":this.loadTemplate("fixedTaskHtml")})}g.innerHTML=t}else g.innerHTML=ksesFilter("No comments");p=document.querySelector(".doboard_task_widget-send_message_input");function N(){40{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0);let s=document.querySelector(".doboard_task_widget-send_message_button");if(s){this.fileUploader.init();let i=this;s.addEventListener("click",async t=>{t.preventDefault();var t=s.closest(".doboard_task_widget-send_message").querySelector(".doboard_task_widget-send_message_input"),a=t.value.trim();if(a){t.disabled=!0,s.disabled=!0;let e=null;try{e=await addTaskComment(this.params,this.currentActiveTaskId,a),t.value="",await this.createWidgetElement("concrete_issue"),hideContainersSpinner(!1)}catch(e){alert("Error when adding a comment: "+e.message)}i.fileUploader.hasFiles()&&null!==e&&e.hasOwnProperty("commentId")&&(a=localStorage.getItem("spotfix_session_id"),(a=await i.fileUploader.sendAttachmentsForComment(i.params,a,e.commentId)).success||(i.fileUploader.showError("Some files where no sent, see details in the console."),a=JSON.stringify(a),console.log(a))),t.disabled=!1,s.disabled=!1}})}}e=document.querySelector(".doboard_task_widget_return_to_all");let s=this;e&&e.addEventListener("click",function(e,t=s){t.createWidgetElement("all_issues")});e=document.querySelector(".doboard_task_widget-send_message_paperclip");return e&&this.fileUploader.bindPaperClipAction(e),document.querySelector(".doboard_task_widget-close_btn")?.addEventListener("click",e=>{this.hide()}),document.querySelector("#openUserMenuButton")?.addEventListener("click",()=>{this.createWidgetElement("user_menu")}),document.querySelector("#doboard_task_widget-user_menu-logout_button")?.addEventListener("click",()=>{logoutUserDoboard(this.params.accountId)}),document.getElementById("addNewTaskButton")?.addEventListener("click",()=>{spotFixShowWidget()}),document.getElementById("maximizeWidgetContainer")?.addEventListener("click",()=>{var e=document.querySelector(".doboard_task_widget-container");+localStorage.getItem("maximize")&&e.classList.contains("doboard_task_widget-container-maximize")?(localStorage.setItem("maximize","0"),e.classList.remove("doboard_task_widget-container-maximize")):(localStorage.setItem("maximize","1"),e.classList.add("doboard_task_widget-container-maximize"))}),document.querySelector("#doboard_task_widget-user_menu-signlog_button")?.addEventListener("click",()=>{spotFixShowWidget()}),document.querySelector("#spotfix_back_button")?.addEventListener("click",()=>{this.createWidgetElement(this.type_name)}),d}bindIssuesClick(){document.querySelectorAll(".issue-item").forEach(e=>{e.addEventListener("click",async()=>{let t=null;try{t=JSON.parse(e.getAttribute("data-node-path"))}catch(e){t=null}t&&spotFixScrollToNodePath(t),this.currentActiveTaskId=e.getAttribute("data-task-id"),await this.showOneTask()})})}async showOneTask(){await this.createWidgetElement("concrete_issue");var e=this.getTaskHighlightData(this.currentActiveTaskId);e&&(spotFixRemoveHighlights(),spotFixHighlightElements([e],this),this.positionWidgetContainer()),hideContainersSpinner(!1)}loadTemplate(t,e={}){let a=SpotFixTemplatesLoader.getTemplateCode(t);for(var[i,o]of Object.entries(e)){i=`{{${i}}}`;let e;e=this.isPlaceholderInAttribute(a,i)?this.escapeHtml(String(o)):ksesFilter(String(o),{template:t,imgFilter:!0}),a=a.replaceAll(i,e)}return ksesFilter(a,{template:t})}isPlaceholderInAttribute(e,t){t=t.replace(/[{}]/g,"\\$&");return new RegExp(`[\\w-]+\\s*=\\s*["'][^"']*${t}[^"']*["']`,"g").test(e)}escapeHtml=e=>e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");async getTaskCount(){if(!localStorage.getItem("spotfix_session_id"))return{};var e=this.params.projectToken,t=localStorage.getItem("spotfix_session_id"),a=localStorage.getItem("spotfix_tasks_count");let i;i=0===a||a?a:(await getTasksDoboard(e,t,this.params.accountId,this.params.projectId)).filter(e=>e.taskMeta).length;a=document.getElementById("doboard_task_widget-task_count");a&&(a.innerText=ksesFilter(i),a.classList.remove("hidden"))}async submitTask(e){localStorage.getItem("spotfix_session_id")||(await registerUser(e)(this.registrationShowMessage),e.userPassword&&await loginUser(e)(this.registrationShowMessage));var t=localStorage.getItem("spotfix_session_id");return t?handleCreateTask(t,e):{needToLogin:!0}}hide(){spotFixRemoveHighlights(),this.createWidgetElement("wrap")}wrapElementWithSpotfixHighlight(e){var t=e.cloneNode(),a=document.createElement("span");return a.className="doboard_task_widget-text_selection image-highlight",e.insertAdjacentElement("beforebegin",a),a.appendChild(t),a}getTaskHighlightData(t){var e=this.allTasksData.find(e=>e.taskId.toString()===t.toString());if(e&&void 0!==e.taskMeta){let t=null;try{t=JSON.parse(e.taskMeta)}catch(e){t=null}if(null!==t&&"object"==typeof t)return t}return null}bindWidgetInputsInteractive(){document.querySelectorAll(".doboard_task_widget-field").forEach(e=>{e.value&&e.classList.add("has-value"),e.addEventListener("input",()=>{e.value?e.classList.add("has-value"):e.classList.remove("has-value")}),e.addEventListener("blur",()=>{e.value||e.classList.remove("has-value")})});var t=document.querySelector(".doboard_task_widget-login span");if(t){let e=this;t.addEventListener("click",function(){this.closest(".doboard_task_widget-login").classList.toggle("active"),e.positionWidgetContainer(),setTimeout(()=>{var e=document.querySelector(".doboard_task_widget-content");e.scrollTo({top:e.scrollHeight,behavior:"smooth"})},0)})}window.addEventListener("scroll",this.handleScroll.bind(this)),window.addEventListener("resize",this.handleResize.bind(this))}registrationShowMessage(e,t="error"){var a=document.getElementById("doboard_task_widget-error_message-header"),i=document.getElementById("doboard_task_widget-error_message"),o=document.querySelector(".doboard_task_widget-message-wrapper");"string"==typeof e&&null!==i&&null!==o&&(i.innerText=ksesFilter(e),o.classList.remove("hidden"),i.classList.remove("doboard_task_widget-notice_message","doboard_task_widget-error_message"),"notice"===t?(a.innerText=ksesFilter(""),o.classList.add("doboard_task_widget-notice_message"),i.style.color="#2a5db0"):(a.innerText=ksesFilter("Registration error"),o.classList.add("doboard_task_widget-error_message"),i.style.color="red"))}positionWidgetContainer(){var t=document.querySelector(".doboard_task_widget-text_selection"),a=document.querySelector(".doboard_task_widget"),i=document.querySelector(".doboard_task_widget-content.doboard_task_widget-create_issue"),o=document.querySelector(".doboard_task_widget-concrete_issues-container");if((i||o)&&t){var i=window.scrollY,o=window.innerHeight,t=t.getBoundingClientRect().top+i,s=a.offsetHeight;let e;t-i<0?e=10:(o{this.positionWidgetContainer()},10)}handleResize(){clearTimeout(this.resizeTimeout),this.resizeTimeout=setTimeout(()=>{this.positionWidgetContainer()},100)}isSpotHaveToBeHighlighted(e){return!0}sanitizeNodePath(e){e=Array.isArray(e)?JSON.stringify(e):String(e);return/^[\[\]0-9,\s]*$/.test(e)?e:""}}var spotFixShowDelayTimeout=null;let SPOTFIX_DEBUG=!1,SPOTFIX_SHOW_DELAY=1e3;function spotFixInit(){new SpotFixSourcesLoader,new CleanTalkWidgetDoboard({},"wrap")}function spotFixShowWidget(){new CleanTalkWidgetDoboard(null,"create_issue")}function spotFixIsInsideWidget(t){if(t){let e=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;for(;e;){if(e.classList&&e.classList.contains("doboard_task_widget"))return!0;e=e.parentElement}}return!1}function spotFixOpenWidget(e,t){e&&new CleanTalkWidgetDoboard(e,t)}function spotFixDebugLog(e){SPOTFIX_DEBUG&&console.log(e)}function hideContainersSpinner(){var t=document.getElementsByClassName("doboard_task_widget-spinner_wrapper_for_containers");if(0e?.taskId?.toString()===t?.toString());let o=e.users,i=0String(e.user_id)===String(i.userId))),"");i&&((e=formatDate(i.commentDate)).date,r=e.time);var e=getAvatarSrc(s),d=getAuthorName(s);return{taskId:t,taskAuthorAvatarImgSrc:e,taskAuthorName:d,lastMessageText:i?i.commentBody:"No messages yet",lastMessageTime:r,issueTitle:0new Date(e.commentDate)-new Date(t.commentDate)).map(t=>{var{date:e,time:a}=formatDate(t.commentDate);let i=null;return{commentAuthorAvatarSrc:getAvatarSrc(i=o&&0String(e.user_id)===String(t.userId)):i),commentAuthorName:getAuthorName(i),commentBody:t.commentBody,commentDate:e,commentTime:a,commentUserId:t.userId||"Unknown User"}})}}function getAvatarData(e){let t,a;var i=e.taskAuthorName&&"Anonymous"!=e.taskAuthorName?e.taskAuthorName.trim().charAt(0).toUpperCase():null;let o="doboard_task_widget-avatar-initials";return null===e.taskAuthorAvatarImgSrc&&null!==i&&(t="display: flex;background-color: #f8de7e;justify-content: center;align-items: center;",a="doboard_task_widget-avatar_container"),null===e.taskAuthorAvatarImgSrc&&null===i&&(t="background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAE9GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4wLWMwMDAgNzkuMTcxYzI3ZmFiLCAyMDIyLzA4LzE2LTIyOjM1OjQxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDQtMTBUMTk6MDg6MDkrMDU6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI0LTA0LTEwVDE5OjIxOjA4KzA1OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxNWRjOWI0Yy04ZWVmLTRkNTEtYmE0MS1kOTkzZTZmNjNmMTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTVkYzliNGMt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');",a="doboard_task_widget-avatar_container",o+=" doboard_task_widget-hidden_element"),null!==e.taskAuthorAvatarImgSrc&&(t=`background-image:url('${e.taskAuthorAvatarImgSrc}');`,a="doboard_task_widget-avatar_container",o="doboard_task_widget-hidden_element"),{avatarStyle:t,avatarCSSClass:a,taskAuthorInitials:i,initialsClass:o}}function isAnyTaskUpdated(t){var a=[];for(let e=0;e{var t=e.name.toLowerCase();l[a]?.includes(t)&&!t.startsWith("on")&&!e.value.toLowerCase().includes("javascript:")||i.removeAttribute(e.name)})}[...i.childNodes].forEach(e)}),c.body.innerHTML}"loading"!==document.readyState?document.addEventListener("spotFixLoaded",spotFixInit):document.addEventListener("DOMContentLoaded",spotFixInit),document.addEventListener("selectionchange",function(e){var t;e.target===document&&(e=!!document.getElementsByClassName("wrap_review")[0],(t=document.getSelection())&&""!==t.toString()||!e?(spotFixShowDelayTimeout&&clearTimeout(spotFixShowDelayTimeout),spotFixShowDelayTimeout=setTimeout(()=>{var e,t,a=window.getSelection();"Range"===a.type&&(t=a.anchorNode,e=a.focusNode,spotFixIsInsideWidget(t)||spotFixIsInsideWidget(e)||(t=spotFixGetSelectedData(a))&&spotFixOpenWidget(t,"wrap_review"))},SPOTFIX_SHOW_DELAY)):new CleanTalkWidgetDoboard({},"wrap"))});let SPOTFIX_SELECTION_TYPE_TEXT="text",SPOTFIX_SELECTION_TYPE_IMG="image",SPOTFIX_SELECTION_TYPE_ELEMENT="element";function spotFixGetSelectionType(e){var t=e.getRangeAt(0),a=t.commonAncestorContainer;return spotFixGetSelectedImage(e)?SPOTFIX_SELECTION_TYPE_IMG:a.nodeType===Node.ELEMENT_NODE&&1s&&(s=i.length),r=spotFixCalculateNodePath(n);break;case SPOTFIX_SELECTION_TYPE_IMG:var n=t.startContainer,l=spotFixGetSelectedImage(e);i=`Image (${l.alt||"no description"})`,r=spotFixCalculateNodePath(l),o=Array.from(n.parentNode.children).indexOf(n),s=o+1;break;case SPOTFIX_SELECTION_TYPE_ELEMENT:l=d.nodeType===Node.ELEMENT_NODE?d:d.parentElement;if(l.childNodes.length<=1)return spotFixDebugLog("`spotFixGetSelectedData` skip by `Selection have not inner data`"),null;i=l.textContent||"",r=spotFixCalculateNodePath(l),o=Array.from(l.parentNode.children).indexOf(l),s=o+1}var c=window.location.href;return{startSelectPosition:o,endSelectPosition:s,selectedText:i.trim(),pageURL:c,nodePath:r,selectionType:a,imageUrl:(SPOTFIX_SELECTION_TYPE_IMG,"")}}function spotFixHighlightElements(e,i){if(0!==e.length){let a=new Map;e.forEach(e=>{var t;e?.nodePath&&Array.isArray(e?.nodePath)?this.spotFixIsValidNodePath(e.nodePath)?(t=spotFixRetrieveNodeFromPath(e.nodePath))?e.selectionType?e.selectionType&&![SPOTFIX_SELECTION_TYPE_TEXT,SPOTFIX_SELECTION_TYPE_IMG,SPOTFIX_SELECTION_TYPE_ELEMENT].includes(e.selectionType)?spotFixDebugLog("Invalid selection type: "+e.selectionType):(a.has(t)||a.set(t,[]),a.get(t).push(e)):spotFixDebugLog("Selection type is not provided."):spotFixDebugLog("Element not found for path: "+e.nodePath):spotFixDebugLog("Invalid nodePath format: "+e.nodePath):spotFixDebugLog("Invalid spot: missing or invalid nodePath: "+e)}),a.forEach((e,t)=>{var a=e[0].selectionType;switch(a){case"image":this.spotFixHighlightImageElement(t);break;case"element":this.spotFixHighlightNestedElement(t);break;case"text":this.spotFixHighlightTextInElement(t,e,i);break;default:spotFixDebugLog("Unknown selection type: "+a)}})}}function spotFixHighlightImageElement(e){"IMG"!==e.tagName?spotFixDebugLog("Expected IMG element for image highlight, got: "+e.tagName):e.classList.add("doboard_task_widget-image_selection")}function spotFixHighlightNestedElement(e){e.classList.add("doboard_task_widget-element_selection")}function spotFixHighlightTextInElement(e,t,o){let a="";let s=`${`
${a=t[0].isFixed?"This issue already fixed.":"We are already working on this issue."}
diff --git a/dist/doboard-widget-bundle.min.js.map b/dist/doboard-widget-bundle.min.js.map index e9273ca..2f6b5fa 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: '',\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 || '';\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/widget.js b/js/src/widget.js index 036257b..629869a 100644 --- a/js/src/widget.js +++ b/js/src/widget.js @@ -331,7 +331,7 @@ class CleanTalkWidgetDoboard { chevronBackDark: SpotFixSVGLoader.getAsDataURI('chevronBackDark'), buttonCloseScreen: SpotFixSVGLoader.getAsDataURI('buttonCloseScreen'), userName: 'Guest', - email: '', + email: localStorage.getItem('spotfix_email') || '', ...this.srcVariables}; break; case 'concrete_issue': @@ -531,7 +531,7 @@ class CleanTalkWidgetDoboard { if(user){ templateVariables.userName = user.name || 'Guest'; - templateVariables.email = user.email || ''; + templateVariables.email = user.email || localStorage.getItem('spotfix_email') || ''; if(user?.avatar?.s) templateVariables.avatar = user?.avatar?.s; }