Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 146 additions & 70 deletions dist/doboard-widget-bundle.js

Large diffs are not rendered by default.

20 changes: 11 additions & 9 deletions dist/doboard-widget-bundle.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/doboard-widget-bundle.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ const getTasksAttachmenDoboard = async (sessionId, accountId, projectToken, curr
task_id: currentActiveTaskId
}
const result = await spotfixApiCall(data, 'attachment_get', accountId);

const attachment = result.attachments.map((item, index) => ({
attachmentId: item.attachment_id || `att_${item.task_id}_${index}_${Date.now()}`,
taskId: item.task_id,
Expand Down
181 changes: 116 additions & 65 deletions js/src/selections.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,14 @@ function spotFixGetSelectedData(selection) {

const range = selection.getRangeAt(0);
// Selection must be within a single DOM element.
if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }
const commonNode = range.commonAncestorContainer;
const commonElement = commonNode.nodeType === Node.ELEMENT_NODE ? commonNode : commonNode.parentElement;
if (commonElement === document.body && range.startContainer !== range.endContainer) {
spotFixDebugLog('`spotFixGetSelectedData` skip: Selection is too broad');
return null;
}

// if (range.startContainer !== range.endContainer) { spotFixDebugLog('`spotFixGetSelectedData` skip by `Selection within several tags nodes`'); return null; }
Comment on lines 61 to +70
Comment on lines +63 to +70
Comment on lines +63 to +70

Comment on lines +70 to 71
Comment on lines +70 to 71
// FIRST - check selection type
const selectionType = spotFixGetSelectionType(selection);
Expand All @@ -75,8 +82,6 @@ function spotFixGetSelectedData(selection) {
let nodePath = '';
let imageUrl = '';

const commonNode = range.commonAncestorContainer;

switch (selectionType) {
case SPOTFIX_SELECTION_TYPE_TEXT:
if (range.toString().trim().length === 0) {
Expand Down Expand Up @@ -205,17 +210,21 @@ function spotFixHighlightElements(spotsToBeHighlighted, widgetInstance) {

// MAIN LOGIC: highlight for the different types
switch (selectionType) {
case 'image':
this.spotFixHighlightImageElement(element);
break;
case 'image':
this.spotFixHighlightImageElement(element);
break;

case 'element':
this.spotFixHighlightNestedElement(element);
break;
case 'element':
this.spotFixHighlightNestedElement(element);
break;

case 'text':
this.spotFixHighlightTextInElement(element, spots, widgetInstance);
break;
case 'text':
const uniqueSpot = [spots[0]];
try {
this.spotFixHighlightTextInElement(element, uniqueSpot, widgetInstance);
Comment on lines +222 to +224
Comment on lines +222 to +224
} catch (e) {
}
break;

default:
spotFixDebugLog('Unknown selection type: ' + selectionType);
Comment on lines +221 to 230
Expand Down Expand Up @@ -249,93 +258,135 @@ function spotFixHighlightNestedElement(element) {
* @param {Array} spots
* @param widgetInstance
*/
function spotFixHighlightTextInElement(element, spots,widgetInstance) {
let tooltipTitleText = '';
if (spots[0].isFixed) {
tooltipTitleText = `This issue already fixed.`;
} else {
tooltipTitleText = `We are already working on this issue.`;
function spotFixHighlightTextInElement(element, spots, widgetInstance) {
if (!spots || spots.length === 0) return;

const listTags = ['LI', 'OL', 'UL'];
if (listTags.includes(element.tagName)) {
const span = document.createElement('span');
span.textContent = element.textContent;
if (element.id) span.id = element.id;
element.parentNode.replaceChild(span, element);
element = span;
}

const tooltip = `<div class="doboard_task_widget-text_selection_tooltip_element">
<span class="doboard_task_widget-text_selection_tooltip_icon"></span>
<span>
<div>${tooltipTitleText}</div>
<div>You can see history <span class="doboard_task_widget-see-task doboard_task_widget-see-task__task-id-${spots[0].taskId}">Here</span></div>
</span>
</div>`;

const spotfixHighlightOpen = `<span class="doboard_task_widget-text_selection"><span class="doboard_task_widget-text_selection_tooltip">${tooltip}</span>`;
const spotfixHighlightClose = `</span>`;

let text = element.textContent;
const originalText = element.textContent;
const spotSelectedText = spots[0].selectedText;

// meta.selectedText can not be empty string
if ( ! spotSelectedText ) {
if (!spotSelectedText) {
spotFixDebugLog('Provided metadata is invalid.');
return;
}

const markers = [];
const validRanges = [];

// Mark positions for inserting
spots.forEach(spot => {
// Validating positions
const startPos = parseInt(spot.startSelectPosition) || 0;
const endPos = parseInt(spot.endSelectPosition) || 0;

if (startPos < 0 || endPos > text.length || startPos > endPos) {
if (startPos < 0 || endPos > originalText.length || startPos > endPos) {
spotFixDebugLog('Invalid text positions: ' + spot);
return;
}

markers.push({ position: startPos, type: 'start' });
markers.push({ position: endPos, type: 'end' });
validRanges.push({ startPos, endPos });
});

if (markers.length === 0) return;
if (validRanges.length === 0) return;

validRanges.sort((a, b) => b.startPos - a.startPos);

// Sort markers backward
markers.sort((a, b) => b.position - a.position);
const minStart = validRanges[validRanges.length - 1].startPos;
const maxEnd = validRanges[0].endPos;

// Check here that element (from meta.nodePath) contains same inner text as in meta.selectedText
// Is the `text` in the element equal to the selected text `spotSelectedText`
if ( text.slice(markers[1].position, markers[0].position) !== spotSelectedText ) {
if (originalText.slice(minStart, maxEnd) !== spotSelectedText) {
spotFixDebugLog('It is not allow to highlight element by provided metadata.');
return;
}

let result = text;
markers.forEach(marker => {
const insertText = marker.type === 'start'
? spotfixHighlightOpen
: spotfixHighlightClose;
let tooltipTitleText = spots[0].isFixed
? `This issue already fixed.`
: `We are already working on this issue.`;

const tooltipHtml = `
<div class="doboard_task_widget-text_selection_tooltip_element">
<span class="doboard_task_widget-text_selection_tooltip_icon"></span>
<span>
<div>${tooltipTitleText}</div>
<div>You can see history <span class="doboard_task_widget-see-task doboard_task_widget-see-task__task-id-${spots[0].taskId}">Here</span></div>
</span>
</div>
`;

validRanges.forEach(rangeData => {
const {startPos, endPos} = rangeData;
const highlightWrapper = document.createElement('span');
highlightWrapper.className = 'doboard_task_widget-text_selection';

const tooltipSpan = document.createElement('span');
tooltipSpan.className = 'doboard_task_widget-text_selection_tooltip';
tooltipSpan.innerHTML = tooltipHtml;
highlightWrapper.appendChild(tooltipSpan);

const range = document.createRange();

if (element.nodeType === Node.TEXT_NODE) {
try {
range.setStart(element, startPos);
range.setEnd(element, endPos);
const contents = range.extractContents();
highlightWrapper.appendChild(contents);
range.insertNode(highlightWrapper);
setupLinkListener(tooltipSpan);
} catch (e) { spotFixDebugLog(e); }
} else {
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
let node;
let currentPos = 0;
let startNode = null, startOffset = 0;
let endNode = null, endOffset = 0;

while ((node = walker.nextNode())) {
let nodeLength = node.nodeValue.length;
if (!startNode && currentPos + nodeLength >= startPos) {
startNode = node;
startOffset = startPos - currentPos;
}
if (!endNode && currentPos + nodeLength >= endPos) {
endNode = node;
endOffset = endPos - currentPos;
break;
}
currentPos += nodeLength;
}

result = result.slice(0, marker.position) + insertText + result.slice(marker.position);
if (startNode && endNode) {
try {
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
const contents = range.extractContents();
highlightWrapper.appendChild(contents);
range.insertNode(highlightWrapper);
setupLinkListener(tooltipSpan);
} catch (error) {
spotFixDebugLog('Error updating element content: ' + error);
}
}
}
});

// Safety HTML insert
try {
element.innerHTML = ksesFilter(result);
document.querySelectorAll('.doboard_task_widget-see-task').forEach(link => {
function setupLinkListener(tooltip) {
const link = tooltip.querySelector('.doboard_task_widget-see-task');
if (link) {
link.addEventListener('click', (e) => {

e.preventDefault();
const classList = link.className.split(' ');
const idClass = classList.find(cls => cls.includes('__task-id-'));
let taskId = null;
const idClass = link.className.split(' ').find(cls => cls.includes('__task-id-'));
if (idClass) {
taskId = idClass.split('__task-id-')[1];
}
if (taskId) {
const taskId = idClass.split('__task-id-')[1];
widgetInstance.currentActiveTaskId = taskId;
widgetInstance.showOneTask();
}
});
});
} catch (error) {
spotFixDebugLog('Error updating element content: ' + error);
}
}
}

Expand Down
31 changes: 28 additions & 3 deletions js/src/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,13 @@ class CleanTalkWidgetDoboard {
finishedContainer.classList.toggle('expanded');
finishedHeader.classList.toggle('expanded');

if (finishedContainer.classList.contains('expanded')) {
spotFixHighlightElements(spotsToBeHighlighted, this);
} else {
spotFixRemoveHighlights();
spotFixHighlightElements(spotsToBeHighlighted.filter(item => !item.isFixed), this);
}

setTimeout(() => {
if (finishedContainer.classList.contains('expanded')) {
const children = finishedContainer.children;
Expand All @@ -1167,7 +1174,13 @@ class CleanTalkWidgetDoboard {

this.savedIssuesQuantityOnPage = issuesQuantityOnPage;
this.savedIssuesQuantityAll = tasks.length;
spotFixHighlightElements(spotsToBeHighlighted, this);
const finishedSpotsListHeader = document.getElementById('finishedTasksHeader');
if (finishedSpotsListHeader?.classList?.contains('expanded')) {
spotFixHighlightElements(spotsToBeHighlighted, this);
} else {
spotFixRemoveHighlights();
spotFixHighlightElements(spotsToBeHighlighted.filter(item => !item.isFixed), this);
}
Comment on lines +1178 to +1183
const headerSpan = document.querySelector('.doboard_task_widget-header span');
if (headerSpan) {
headerSpan.innerHTML = ksesFilter('All spots ' + getIssuesCounterString(this.savedIssuesQuantityOnPage, this.savedIssuesQuantityAll));
Comment on lines +1178 to 1186
Expand Down Expand Up @@ -1966,9 +1979,21 @@ class CleanTalkWidgetDoboard {
});
tasksCount = filteredTasks.length;

let notificationsCount = 0;

if(!this.nonRequesting) {
const activeTasksIds = filteredTasks.map(item => item.taskId);
notificationsCount = await getNotificationsDoboard(this.params.projectToken, sessionId, this.params.accountId, this.params.projectId);
notificationsCount = [...new Map(notificationsCount.map((item) => [item.task_id, item])).values()];
Comment on lines +1986 to +1987
notificationsCount = notificationsCount.filter((item) => activeTasksIds.includes(item.task_id)).length;
localStorage.setItem('spotfix-tasks-notifications-count', `${notificationsCount}`);
} else {
notificationsCount = localStorage.getItem('spotfix-tasks-notifications-count');
Comment thread
veronika-tseleva-cleantalk marked this conversation as resolved.
Comment on lines +1989 to +1991
}
Comment thread
veronika-tseleva-cleantalk marked this conversation as resolved.
Comment on lines +1984 to +1992
Comment on lines +1989 to +1992
Comment on lines +1989 to +1992

const taskCountElement = document.getElementById('doboard_task_widget-task_count');
if ( taskCountElement && +tasksCount ) {
taskCountElement.innerText = ksesFilter(tasksCount);
if ( taskCountElement && +notificationsCount ) {
taskCountElement.innerText = ksesFilter(notificationsCount);
Comment on lines +1990 to +1996
Comment on lines 1980 to +1996
taskCountElement.classList.remove('hidden');
if (localStorage.getItem('horizontalPosition') === 'left' || window.SpotfixWidgetConfig?.horizontalPosition === 'left') taskCountElement.style.left = '10px';
Comment on lines +1995 to 1998
}
Expand Down
1 change: 1 addition & 0 deletions styles/doboard-widget.css
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
display: flex;
flex-direction: column;
-moz-flex-direction: column;
min-height: 490px;
}

.doboard_task_widget-header {
Expand Down