UNPKG

@syncfusion/ej2-spreadsheet

Version:

Feature-rich JavaScript Spreadsheet (Excel) control with built-in support for selection, editing, formatting, importing and exporting to Excel

1,001 lines 111 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import { activeCellChanged, beginAction, getCell, getCellAddress, getCellIndexes, getRowHeight, getSheetName, importModelUpdate, setCell } from '../../workbook/index'; import { initiateComment, completeAction, createCommentIndicator, deleteComment, removeCommentContainer, locale, replyToComment, showCommentsPane, refreshCommentsPane, commentUndoRedo, getDPRValue, processSheetComments } from '../index'; import { Browser, closest, detach, enableRipple, EventHandler, getComponent, getUniqueID, isNullOrUndefined } from '@syncfusion/ej2-base'; import { getUpdateUsingRaf, navigateNextPrevComment, updateNoteContainer } from './../common/index'; import { getRangeAddress, updateCell } from '../../workbook/index'; import { Button } from '@syncfusion/ej2-buttons'; import { DropDownButton } from '@syncfusion/ej2-splitbuttons'; import { ListView, Virtualization } from '@syncfusion/ej2-lists'; ListView.Inject(Virtualization); /** * Comment module. */ var SpreadsheetComment = /** @class */ (function () { /** * Initializes a new instance of the `SpreadsheetComment` class * * @param {Spreadsheet} parent - Constructor for SpreadsheetComment module. */ function SpreadsheetComment(parent) { /** @hidden */ this.isCommentVisible = false; /** @hidden */ this.isCommentVisibleOnTouch = false; /** @hidden */ this.isReviewPaneVisible = false; this.isEditing = false; this.reviewInstances = []; this.reviewFilter = 'all'; this.scheduleMountId = 0; this.parent = parent; this.addEventListener(); } SpreadsheetComment.prototype.addEventListener = function () { this.parent.on(initiateComment, this.initiateComment, this); this.parent.on(deleteComment, this.deleteComment, this); this.parent.on(createCommentIndicator, this.createCommentIndicator, this); this.parent.on(removeCommentContainer, this.removeCommentContainer, this); this.parent.on(replyToComment, this.replyToComment, this); this.parent.on(importModelUpdate, this.updateCommentsFromSheet, this); this.parent.on(showCommentsPane, this.showCommentPane, this); this.parent.on(navigateNextPrevComment, this.navigateNextPrevComment, this); this.parent.on(refreshCommentsPane, this.refreshCommentsPane, this); this.parent.on(processSheetComments, this.processSheetComments, this); this.parent.on(commentUndoRedo, this.onCommentUndoRedo, this); this.parent.on(activeCellChanged, this.commentHandler, this); }; SpreadsheetComment.prototype.removeEventListener = function () { if (!this.parent.isDestroyed) { this.parent.off(initiateComment, this.initiateComment); this.parent.off(deleteComment, this.deleteComment); this.parent.off(createCommentIndicator, this.createCommentIndicator); this.parent.off(removeCommentContainer, this.removeCommentContainer); this.parent.off(replyToComment, this.replyToComment); this.parent.off(importModelUpdate, this.updateCommentsFromSheet); this.parent.off(showCommentsPane, this.showCommentPane); this.parent.off(navigateNextPrevComment, this.navigateNextPrevComment); this.parent.off(refreshCommentsPane, this.refreshCommentsPane); this.parent.off(processSheetComments, this.processSheetComments); this.parent.off(commentUndoRedo, this.onCommentUndoRedo); this.parent.off(activeCellChanged, this.commentHandler); } }; SpreadsheetComment.prototype.initiateComment = function (args) { var cellIndexes = (args && !isNullOrUndefined(args.rowIndex) && !isNullOrUndefined(args.columnIndex)) ? [args.rowIndex, args.columnIndex] : getCellIndexes(this.parent.getActiveSheet().activeCell); var targetElement = this.parent.getCell(cellIndexes[0], cellIndexes[1]); if (!isNullOrUndefined(targetElement)) { if (!targetElement.querySelector('.e-comment-indicator')) { this.createCommentIndicator({ targetEle: targetElement, rIdx: cellIndexes[0], cIdx: cellIndexes[1] }); } if (args && args.isMouseOver) { this.createCommentContainer(targetElement, cellIndexes[0], cellIndexes[1]); this.activeCommentCell = [cellIndexes[0], cellIndexes[1]]; return; } if (this.isReviewPaneVisible) { var sheet = this.parent.getActiveSheet(); var existing = (sheet.comments || []).find(function (t) { return t.address && t.address[0] === cellIndexes[0] && t.address[1] === cellIndexes[1]; }); if (existing && existing.id) { this.scrollToThreadInPanel(existing.id, args && args.isSelection); } else { this.renderNewCommentForPanel(cellIndexes[0], cellIndexes[1]); } } else { this.createCommentContainer(targetElement, cellIndexes[0], cellIndexes[1]); this.activeCommentCell = [cellIndexes[0], cellIndexes[1]]; } } }; SpreadsheetComment.prototype.createCommentIndicator = function (args) { var commentIndicator = this.parent.createElement('div', { className: 'e-comment-indicator' }); if (args.targetEle.children.length > 0) { var rowHeight = getRowHeight(this.parent.getActiveSheet(), args.rIdx); var defaultFilterButtonHeight = 20; for (var i = 0; i < args.targetEle.childElementCount; i++) { var children = args.targetEle.children[i]; if (children.className.indexOf('e-filter-btn') > -1) { if (this.parent.enableRtl) { commentIndicator.style.left = (rowHeight < (defaultFilterButtonHeight + 10) ? (children.getBoundingClientRect().width <= 0 ? defaultFilterButtonHeight : children.getBoundingClientRect().width + 1) : 2) + 'px'; } else { commentIndicator.style.right = (rowHeight < (defaultFilterButtonHeight + 10) ? (children.getBoundingClientRect().width <= 0 ? defaultFilterButtonHeight : children.getBoundingClientRect().width + 1) : 2) + 'px'; } } if (children.className.indexOf('e-validation-list') > -1) { if (this.parent.enableRtl) { commentIndicator.style.left = (children.getBoundingClientRect().width || 20) + 2 + "px"; } else { commentIndicator.style.right = (children.getBoundingClientRect().width || 20) + 2 + "px"; } } } } if (!commentIndicator.dataset.commentListenersAdded && !args.skipEvent) { commentIndicator.dataset.commentRowIndex = args.rIdx.toString(); commentIndicator.dataset.commentColIndex = args.cIdx.toString(); EventHandler.add(commentIndicator, 'mouseover', this.mouseOver, this); EventHandler.add(commentIndicator, 'mouseout', this.mouseOut, this); commentIndicator.dataset.commentListenersAdded = 'true'; } args.targetEle.appendChild(commentIndicator); }; SpreadsheetComment.prototype.mouseOver = function (event) { var cell = event.currentTarget; var row = parseInt(cell.dataset.commentRowIndex, 10); var col = parseInt(cell.dataset.commentColIndex, 10); if (!isNaN(row) && !isNaN(col)) { var containerInDOM = document.getElementsByClassName('e-comment-container')[0]; if ((this.isCommentVisibleOnTouch && !isNullOrUndefined(containerInDOM)) || isNullOrUndefined(containerInDOM)) { if (!isNullOrUndefined(containerInDOM)) { this.removeCommentContainer(); } this.initiateComment({ rowIndex: row, columnIndex: col, isMouseOver: true }); this.isCommentVisible = true; } } }; SpreadsheetComment.prototype.mouseOut = function (e) { var commentContainer = this.getCommentContainer(); var relatedTarget = e.relatedTarget; if (this.isCommentVisible && (!this.isCommentVisibleOnTouch && commentContainer)) { if (relatedTarget) { var isInsideContainer = commentContainer.contains(relatedTarget); var isInsideIndicator = closest(relatedTarget, '.e-comment-indicator'); var isInsideDropDownPopup = closest(relatedTarget, '.e-dropdown-popup'); var isCommentCell = this.parent.getCell(this.activeCommentCell[0], this.activeCommentCell[1]); if (!isInsideContainer && !isInsideIndicator && !isInsideDropDownPopup && isCommentCell && !isCommentCell.contains(relatedTarget) && document.activeElement !== commentContainer && document.activeElement !== commentContainer.querySelector('.e-comment-input')) { this.removeCommentContainer(); this.isCommentVisible = false; this.activeCommentCell = null; } } } }; SpreadsheetComment.prototype.createCommentContainer = function (targetEle, rIdx, cIdx) { var commentContainer = this.parent.createElement('div', { className: 'e-comment-container' }); commentContainer.tabIndex = -1; this.renderCommentUI(commentContainer, rIdx, cIdx, false); commentContainer.style.visibility = 'hidden'; this.parent.element.appendChild(commentContainer); this.setCommentContainerPosition(commentContainer, targetEle.getBoundingClientRect()); commentContainer.style.visibility = ''; var cell = getCell(rIdx, cIdx, this.parent.getActiveSheet()); var thread = cell && cell.comment; if (thread && thread.isResolved) { this.handleResolvedThread(commentContainer, rIdx, cIdx, thread); } var textArea = commentContainer.querySelector('.e-comment-footer .e-comment-input'); if (textArea && (!cell || (cell && !cell.comment))) { textArea.focus(); textArea.select(); if (!commentContainer.classList.contains('active')) { commentContainer.classList.add('active'); } } this.bindContainerEvents(commentContainer); EventHandler.add(commentContainer, 'mouseout', this.mouseOut, this); EventHandler.add(targetEle, 'mouseout', this.mouseOut, this); this.isCommentVisible = true; }; SpreadsheetComment.prototype.handleResolvedThread = function (container, rIdx, cIdx, thread) { var headerEl = container.querySelector('.e-comment-header'); if (headerEl) { headerEl.replaceWith(this.createheaderContent(false, getCellAddress(rIdx, cIdx), thread)); } var footerEl = container.querySelector('.e-comment-footer'); if (footerEl) { this.unwireFooterEvents(footerEl); this.removeFooterButtons(footerEl); footerEl.remove(); } container.classList.add('e-thread-resolved'); this.removeReplyButtons(container.querySelector('.e-comment-body')); this.setTextAreaState(container, true); this.renderResolvedWrap(container, rIdx, cIdx, thread.author || (this.parent.author || 'Guest User')); }; SpreadsheetComment.prototype.renderCommentUI = function (container, rIdx, cIdx, inPane, containerId) { var sheet = this.parent.getActiveSheet(); var cell = getCell(rIdx, cIdx, sheet); var header; var body; var footer; if (cell && cell.comment) { var cellAddress = getCellAddress(rIdx, cIdx); header = this.createheaderContent(false, cellAddress, cell.comment); body = this.createBodyContent(cell.comment, true, inPane, containerId); footer = this.createFooterContent(rIdx, cIdx, false); } else { header = this.createheaderContent(true); footer = this.createFooterContent(rIdx, cIdx, true); } if (!inPane) { container.dataset.commentRowIndex = rIdx.toString(); container.dataset.commentColIndex = cIdx.toString(); } container.appendChild(header); if (body) { container.appendChild(body); } container.appendChild(footer); }; SpreadsheetComment.prototype.createheaderContent = function (initial, cellAddress, comment) { var header = this.parent.createElement('div', { className: 'e-comment-header' }); var headerwrap = this.parent.createElement('div', { className: 'e-comment-header-wrap' }); var titleWrap = this.parent.createElement('div', { className: 'e-comment-title-wrap' }); var thread = comment; if (!initial && thread && thread.isResolved) { var l10n = this.parent.serviceLocator.getService(locale); var resolvedWrap = this.parent.createElement('div', { className: 'e-comment-resolved' }); var tick = this.parent.createElement('span', { className: 'e-icons e-check' }); var label = this.parent.createElement('div', { className: 'e-resolve-text' }); label.textContent = l10n.getConstant('Resolved'); resolvedWrap.appendChild(tick); resolvedWrap.appendChild(label); headerwrap.appendChild(resolvedWrap); this.renderHeaderActions(headerwrap, false, '', thread); header.appendChild(headerwrap); return header; } var authorName = initial ? (this.parent.author || 'Guest User') : (thread && thread.author); var avatar = this.getAvatar(authorName); var title = this.parent.createElement('div', { className: 'e-comment-title' }); title.textContent = authorName; titleWrap.appendChild(title); headerwrap.appendChild(titleWrap); this.renderHeaderActions(headerwrap, initial, cellAddress, thread); header.appendChild(avatar); header.appendChild(headerwrap); return header; }; SpreadsheetComment.prototype.getAvatar = function (author) { var avatar = this.parent.createElement('div', { className: 'e-comment-avatar' }); avatar.textContent = this.getAvatarInitials(author); var currentUser = this.parent.author || 'Guest User'; if (author === currentUser) { avatar.style.backgroundColor = '#b5082e'; } else { avatar.style.backgroundColor = this.getAuthorColor(author); } return avatar; }; SpreadsheetComment.prototype.getAuthorColor = function (author) { var colors = ['#b5082e', '#2e97d3', '#bb00ff', '#f37e43', '#03a60b', '#881824', '#e09a2b', '#50565e', '#1f7a8c', '#7b5ea7', '#2db36c', '#d9480f', '#0a58ca', '#a83279', '#00897b']; var authorStr = (author ? author : 'Guest User').trim().toLowerCase(); var hash = 5381; for (var i = 0; i < authorStr.length; i++) { var code = authorStr.charCodeAt(i); hash = (hash * 33 + code) % 4294967296; } var idx = Math.abs(hash) % colors.length; return colors[idx]; }; SpreadsheetComment.prototype.getAvatarInitials = function (name) { var parts = (name ? name : 'Guest User').trim().split(' '); if (parts && parts.length === 1) { return parts[0].charAt(0).toUpperCase(); } return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase(); }; SpreadsheetComment.prototype.renderHeaderActions = function (headerWrap, initial, address, thread) { var _this = this; var l10n = this.parent.serviceLocator.getService(locale); var parentHeader = headerWrap.closest('.e-comment-header'); var existingActions = headerWrap.querySelector('.e-comment-actions'); if (existingActions) { existingActions.remove(); } if (initial) { if (parentHeader) { var existingCloseBtn = parentHeader.querySelector('.e-comment-cancel'); if (existingCloseBtn) { existingCloseBtn.remove(); } } var cancelBtn_1 = this.parent.createElement('button', { className: 'e-comment-cancel', attrs: { 'aria-label': 'Cancel', title: l10n.getConstant('Cancel') } }); var button = new Button({ cssClass: 'e-flat', iconCss: 'e-icons e-close' }, cancelBtn_1); button.createElement = this.parent.createElement; EventHandler.add(button.element, 'click', function () { return _this.handleInitialCancel(cancelBtn_1); }, this); headerWrap.appendChild(cancelBtn_1); return; } if (parentHeader) { var existingCloseBtn = parentHeader.querySelector('.e-comment-cancel'); if (existingCloseBtn) { existingCloseBtn.remove(); } } var actionsWrap = this.parent.createElement('div', { className: 'e-comment-actions' }); if (this.isEditing) { headerWrap.appendChild(actionsWrap); return; } if (thread && thread.isResolved === true) { var reopenBtnEl_1 = this.parent.createElement('button', { className: 'e-comment-reopen-btn', attrs: { type: 'button', title: l10n.getConstant('Reopen') } }); var reopenBtn = new Button({ cssClass: 'e-flat', iconCss: 'e-icons e-undo' }, reopenBtnEl_1); reopenBtn.createElement = this.parent.createElement; EventHandler.add(reopenBtn.element, 'click', function () { return _this.setThreadResolved(false, reopenBtnEl_1); }, this); var deleteBtnEl_1 = this.parent.createElement('button', { className: 'e-comment-delete', attrs: { type: 'button', title: l10n.getConstant('DeleteThread') } }); var deleteBtn = new Button({ cssClass: 'e-flat', iconCss: 'e-icons e-trash' }, deleteBtnEl_1); deleteBtn.createElement = this.parent.createElement; EventHandler.add(deleteBtn.element, 'click', function () { return _this.deleteComment({ sourceEl: deleteBtnEl_1 }); }, this); actionsWrap.appendChild(reopenBtnEl_1); actionsWrap.appendChild(deleteBtnEl_1); headerWrap.appendChild(actionsWrap); return; } var cellRef = this.parent.createElement('span', { className: 'e-comment-cellref' }); cellRef.textContent = address; actionsWrap.appendChild(cellRef); var menuBar = this.parent.createElement('button', { className: 'e-comment-menu e-flat', attrs: { type: 'button', title: l10n.getConstant('ThreadAction') } }); var userOption = [ { text: l10n.getConstant('EditComment'), iconCss: 'e-icons e-edit' }, { text: l10n.getConstant('ResolveThread'), iconCss: 'e-icons e-check' }, { text: l10n.getConstant('DeleteThread'), iconCss: 'e-icons e-trash' } ]; var menuItem = new DropDownButton({ items: userOption, iconCss: 'e-icons e-more-horizontal-1', cssClass: 'e-caret-hide e-menu-popup', enableRtl: this.parent.enableRtl, select: function (e) { return _this.onThreadMenuSelect(e, menuBar); }, open: function () { return _this.setPopupPosition(menuItem, menuBar); } }); menuItem.createElement = this.parent.createElement; menuItem.appendTo(menuBar); actionsWrap.appendChild(menuBar); headerWrap.appendChild(actionsWrap); }; SpreadsheetComment.prototype.setPopupPosition = function (ddb, triggerEl) { if (ddb && ddb.dropDown) { var popupEl = ddb.dropDown.element; if (popupEl) { var btnRect = triggerEl.getBoundingClientRect(); var popupRect = popupEl.getBoundingClientRect(); popupEl.style.left = (this.parent.enableRtl ? btnRect.left : btnRect.right - popupRect.width) + "px"; } } }; SpreadsheetComment.prototype.handleInitialCancel = function (ele) { if (ele) { var container = this.getContainer(ele); var indices = this.getIndexesFromContainer(container); var sheet = this.parent.getActiveSheet(); if (indices) { var rowIndex = indices[0], columnIndex = indices[1]; var cell = getCell(rowIndex, columnIndex, sheet); if (!cell || !cell.comment) { this.detachCommentIndicator(rowIndex, columnIndex); } } if (container) { EventHandler.remove(container, 'mouseout', this.mouseOut); this.unbindContainerEvents(container); var host = this.getBodyHost(container); if (host) { this.unbindReplyHover(host); } detach(container); if (this.isReviewPaneVisible && container.classList.contains('e-thread-draft')) { if (!sheet.comments || !sheet.comments.length) { this.renderReviewBody(); } } } if (this.activeReplyDdb) { this.activeReplyDdb.destroy(); this.activeReplyDdb = null; } this.isCommentVisible = false; this.activeCommentCell = null; this.isEditing = false; } }; SpreadsheetComment.prototype.onThreadMenuSelect = function (event, sourceEl) { var l10n = this.parent.serviceLocator.getService(locale); var text = event.item.text; if (text === l10n.getConstant('EditComment')) { this.beginEdit(false, undefined, sourceEl); } else if (text === l10n.getConstant('ResolveThread')) { this.setThreadResolved(true, sourceEl); } else { this.deleteComment({ sourceEl: sourceEl }); } }; SpreadsheetComment.prototype.createBodyContent = function (thread, rebuild, inPane, cId) { var dataSource = thread ? this.convertThreadToListItems(thread) : []; if (inPane) { var host = this.parent.createElement('div', { className: 'e-comment-body' }); if (Browser.isDevice) { host.classList.add('e-device-comment'); } this.initListView(host, dataSource, true); if (!thread.isResolved && !Browser.isDevice) { this.bindReplyHover(host, cId); } return host; } if (!this.bodyHost) { this.bodyHost = this.parent.createElement('div', { className: 'e-comment-body' }); } if (!this.commentListView) { this.commentListView = this.initListView(this.bodyHost, dataSource, false); } else if (rebuild) { this.commentListView.setProperties({ dataSource: dataSource }, true); this.commentListView.refresh(); } if (!thread.isResolved && !Browser.isDevice) { this.bindReplyHover(this.bodyHost); } return this.bodyHost; }; SpreadsheetComment.prototype.initListView = function (host, dataSource, registerForCleanup) { var _this = this; var itemTemplate = function (data) { var l10n = _this.parent.serviceLocator.getService(locale); var actionText = l10n.getConstant('CommentAction'); var root = _this.parent.createElement('div', { className: "e-comment-item " + data.type, attrs: __assign({ 'data-id': data.id }, (data.type === 'reply' ? { 'data-reply-id': data.id } : {})) }); var renderTextAndTimestamp = function (text, createdTime, parent) { var textEl = _this.parent.createElement('div', { className: 'e-comment-text' }); textEl.textContent = text; var tsEl = _this.parent.createElement('span', { className: 'e-comment-timestamp' }); tsEl.textContent = createdTime; parent.appendChild(textEl); parent.appendChild(tsEl); }; if (data.type === 'initial') { renderTextAndTimestamp(data.text, data.createdTime, root); return [root]; } var row = _this.parent.createElement('div', { className: 'e-comment-reply-row' }); var avatarWrap = _this.parent.createElement('div', { className: 'e-comment-avatar-wrap' }); var authorName = data.author; var avatarEl = _this.getAvatar(authorName); avatarWrap.appendChild(avatarEl); var col = _this.parent.createElement('div', { className: 'e-comment-reply-col' }); var header = _this.parent.createElement('div', { className: 'e-comment-header-wrap' }); var titleWrap = _this.parent.createElement('div', { className: 'e-comment-title-wrap' }); var title = _this.parent.createElement('div', { className: 'e-comment-title' }); title.textContent = authorName; titleWrap.appendChild(title); var menuBtn = _this.parent.createElement('button', { className: 'e-reply-ddb e-flat', attrs: { type: 'button', 'data-reply-id': data.id, 'aria-label': actionText } }); if (Browser.isDevice) { _this.renderReplyDdb(menuBtn); } header.appendChild(titleWrap); header.appendChild(menuBtn); var content = _this.parent.createElement('div', { className: 'e-comment-reply-content' }); renderTextAndTimestamp(data.text, data.createdTime, content); col.appendChild(header); col.appendChild(content); row.appendChild(avatarWrap); row.appendChild(col); root.appendChild(row); return [root]; }; enableRipple(false); var listView = new ListView({ dataSource: dataSource, template: itemTemplate, cssClass: 'e-comment-listview', enableRtl: this.parent.enableRtl, enableVirtualization: true, height: '100%', select: function (args) { if (_this.isReviewPaneVisible) { _this.updateCellSelction(args); } } }); listView.createElement = this.parent.createElement; /* eslint-disable */ listView.isInternalTemplate = true; /* eslint-enable */ listView.appendTo(host); if (registerForCleanup) { this.reviewInstances.push({ destroy: function () { listView.destroy(); } }); } return listView; }; SpreadsheetComment.prototype.renderReplyDdb = function (btn) { var _this = this; if (this.isEditing) { btn.style.visibility = 'hidden'; return; } if (btn.dataset.ddbMounted === 'true') { return; } var l10n = this.parent.serviceLocator.getService(locale); var items = [ { id: 'edit-reply', text: l10n.getConstant('EditComment'), iconCss: 'e-icons e-edit' }, { id: 'delete-reply', text: l10n.getConstant('DeleteComment'), iconCss: 'e-icons e-trash' } ]; var ddb = new DropDownButton({ items: items, iconCss: 'e-icons e-more-horizontal-1', cssClass: 'e-caret-hide e-menu-popup', enableRtl: this.parent.enableRtl, select: function (args) { var replyId = btn.getAttribute('data-reply-id') || ''; _this.onReplyMenuSelect(args, replyId, btn); }, open: function () { return _this.setPopupPosition(ddb, btn); } }); ddb.createElement = this.parent.createElement; ddb.appendTo(btn); btn.dataset.ddbMounted = 'true'; this.activeReplyDdb = ddb; }; SpreadsheetComment.prototype.onReplyMenuSelect = function (args, replyId, sourceEl) { var l10n = this.parent.serviceLocator.getService(locale); var text = args.item.text; if (text === l10n.getConstant('EditComment')) { this.beginEdit(true, replyId, sourceEl); } else { this.deleteReplyById(replyId, sourceEl); } }; SpreadsheetComment.prototype.createFooterContent = function (rowIdx, colIdx, initial) { var l10n = this.parent.serviceLocator.getService(locale); var footer = this.parent.createElement('div', { className: 'e-comment-footer' }); var cell = getCell(rowIdx, colIdx, this.parent.getActiveSheet()); if (cell && cell.comment && cell.comment.isResolved === true) { return footer; } footer.setAttribute('data-mode', initial ? 'initial' : 'reply'); var textArea = this.parent.createElement('textarea', { className: 'e-comment-input', attrs: { placeholder: initial ? l10n.getConstant('AddComment') : l10n.getConstant('Reply'), rows: '1', name: 'footerTextArea' } }); textArea.style.height = '32px'; var btnBar = this.parent.createElement('div', { className: 'e-comment-btn' }); footer.appendChild(textArea); footer.appendChild(btnBar); if (initial) { this.ensureFooterButtons(footer, initial); this.syncFooterPostState(footer, textArea); } this.wireFooterEvents(footer); return footer; }; SpreadsheetComment.prototype.convertThreadToListItems = function (thread) { var items = []; items.push({ id: thread.id, type: 'initial', author: thread.author || 'Guest User', text: thread.text, createdTime: thread.createdTime }); var replies = thread.replies || []; if (replies.length > 0) { replies.forEach(function (reply) { items.push({ id: reply.id || getUniqueID('e_spreadsheet_reply'), type: 'reply', author: reply.author || 'Guest User', text: reply.text, createdTime: reply.createdTime }); }); } return items; }; SpreadsheetComment.prototype.postComment = function (rowIdx, colIdx, commentText, container) { if (!commentText) { return; } var timeStampValue = this.timeStamp(); var actionFromPanel = container && container.classList.contains('e-pane-container'); var cell = getCell(rowIdx, colIdx, this.parent.getActiveSheet()); if (cell && cell.comment) { var thread = JSON.parse(JSON.stringify(cell.comment)); if (!Array.isArray(thread.replies)) { thread.replies = []; } var reply = { id: getUniqueID('e_spreadsheet_reply'), author: this.parent.author || 'Guest User', text: commentText, createdTime: timeStampValue }; thread.replies.push(reply); this.saveComment(rowIdx, colIdx, thread, 'addReply', actionFromPanel); var body = container.querySelector('.e-comment-body'); var targetListView = void 0; if (body) { targetListView = getComponent(body, 'listview'); } else { targetListView = this.commentListView; } if (targetListView) { var avatarEl = this.getAvatar(reply.author); targetListView.addItem([{ id: reply.id, type: 'reply', author: reply.author, text: reply.text, createdTime: reply.createdTime, avatarHtml: avatarEl.outerHTML }]); if (body) { body.scrollTop = body.scrollHeight; } } return; } var id = getUniqueID('e_spreadsheet_comment'); var newThread = { id: id, author: this.parent.author || 'Guest User', text: commentText, createdTime: timeStampValue, isResolved: false, replies: [] }; this.saveComment(rowIdx, colIdx, newThread, 'addComment', actionFromPanel); var header = container.querySelector('.e-comment-header'); if (header && !header.querySelector('.e-comment-actions')) { var headerWrap = header.querySelector('.e-comment-header-wrap'); if (headerWrap) { this.renderHeaderActions(headerWrap, false, getCellAddress(rowIdx, colIdx)); } } if (container) { var body = this.createBodyContent(newThread, true, this.isReviewPaneVisible); var footer = container.querySelector('.e-comment-footer'); if (footer && body && body.parentElement !== container) { container.insertBefore(body, footer); } else if (footer && body && footer.previousElementSibling !== body) { container.insertBefore(body, footer); } } if (this.isReviewPaneVisible) { if (container && container.classList.contains('e-thread-draft')) { container.remove(); } } }; SpreadsheetComment.prototype.beginEdit = function (isReply, replyId, sourceEl) { var _this = this; var container = this.getContainer(sourceEl); var localBodyHost = this.getBodyHost(container); if (this.isEditing || !container || !localBodyHost) { return; } var idx = this.getIndexesFromContainer(container); if (idx) { var cell = getCell(idx[0], idx[1], this.parent.getActiveSheet()); var th = cell && cell.comment; if (th && th.isResolved) { return; } } var itemSelector = isReply ? ".e-comment-item.reply[data-reply-id=\"" + replyId + "\"]" : '.e-comment-item.initial'; var itemEl = localBodyHost.querySelector(itemSelector); if (!itemEl) { return; } var textEl = itemEl.querySelector('.e-comment-text'); if (!textEl) { return; } var originalText = textEl.textContent || ''; var l10n = this.parent.serviceLocator.getService(locale); var editorWrap = this.parent.createElement('div', { className: 'e-comment-edit-wrap' }); var textArea = this.parent.createElement('textarea', { className: 'e-comment-input e-comment-edit-input', attrs: { rows: '1', name: 'editTextArea' } }); EventHandler.add(textArea, 'focus', function () { textArea.classList.add('active'); }, this); EventHandler.add(textArea, 'blur', function () { textArea.classList.remove('active'); }, this); textArea.value = originalText; this.adjustTextareaHeight(textArea, true); var tsEle = itemEl.querySelector('.e-comment-timestamp'); var tsValue = ''; if (tsEle) { tsValue = tsEle.style.display; tsEle.style.display = 'none'; } var btnBar = this.parent.createElement('div', { className: 'e-comment-btn' }); var postBtnEl = this.parent.createElement('button', { className: 'e-comment-post', attrs: { type: 'button', 'aria-label': 'Post', title: l10n.getConstant('EditComment') } }); var postBtn = new Button({ iconCss: 'e-icons e-send', isPrimary: true }, postBtnEl); postBtn.createElement = this.parent.createElement; var cancelBtnEl = this.parent.createElement('button', { className: 'e-comment-cancel', attrs: { type: 'button', 'aria-label': 'Cancel', title: l10n.getConstant('Cancel') } }); var cancelBtn = new Button({ cssClass: 'e-flat', iconCss: 'e-icons e-close' }, cancelBtnEl); cancelBtn.createElement = this.parent.createElement; EventHandler.add(textArea, 'input', function () { return _this.adjustTextareaHeight(textArea, true); }, this); EventHandler.add(postBtn.element, 'click', function () { _this.applyInlineEdit(isReply, textArea.value, textEl, editorWrap, originalText, replyId, container); }, this); EventHandler.add(cancelBtn.element, 'click', function () { textEl.textContent = originalText; textEl.style.display = ''; editorWrap.remove(); _this.endEdit(container); }, this); btnBar.appendChild(postBtnEl); btnBar.appendChild(cancelBtnEl); editorWrap.appendChild(textArea); editorWrap.appendChild(btnBar); textEl.style.display = 'none'; if (textEl.parentElement) { textEl.parentElement.insertBefore(editorWrap, textEl.nextSibling); } this.editingState = { isReply: isReply, replyId: replyId, textEl: textEl, editorWrap: editorWrap, originalText: originalText, tsEle: tsEle, tsValue: tsValue, container: container, textHost: localBodyHost, addrIdx: idx }; this.isEditing = true; this.setTextAreaState(container, true); container.classList.add('e-comment-editing'); var header = container.querySelector('.e-comment-header'); if (header) { var headerWrap = header.querySelector('.e-comment-header-wrap'); if (headerWrap) { if (idx && idx.length === 2) { this.renderHeaderActions(headerWrap, false, getCellAddress(idx[0], idx[1])); } } } var replyBtns = localBodyHost.querySelectorAll('.e-reply-ddb'); if (replyBtns) { replyBtns.forEach(function (btn) { btn.style.visibility = 'hidden'; }); } getUpdateUsingRaf(function () { _this.adjustTextareaHeight(textArea, true); textArea.focus(); var len = textArea.value.length; textArea.setSelectionRange(len, len); }); }; SpreadsheetComment.prototype.applyInlineEdit = function (isReply, newText, textEl, editorWrap, originalText, replyId, container) { var finalText = newText || originalText; textEl.textContent = finalText; textEl.style.display = ''; editorWrap.remove(); var indices = this.getIndexesFromContainer(container || null); if (indices && indices.length === 2) { var row = indices[0], col = indices[1]; var cell = getCell(row, col, this.parent.getActiveSheet()); var actionFromPanel = container && container.classList.contains('e-pane-container'); if (cell && cell.comment) { var thread = JSON.parse(JSON.stringify(cell.comment)); if (isReply) { if (!replyId || !thread.replies) { this.endEdit(container); return; } var idx = thread.replies.findIndex(function (r) { return r.id === replyId; }); if (idx > -1) { thread.replies[idx] = __assign({}, thread.replies[idx], { text: finalText }); this.saveComment(row, col, thread, 'editReply', actionFromPanel); } } else { var updatedThread = __assign({}, thread, { text: finalText }); this.saveComment(row, col, updatedThread, 'editComment', actionFromPanel); } } } this.endEdit(container); }; SpreadsheetComment.prototype.endEdit = function (container) { if (this.editingState && this.editingState.tsEle) { this.editingState.tsEle.style.display = isNullOrUndefined(this.editingState.tsValue) ? '' : this.editingState.tsValue; } var targetContainer = container || (this.editingState && this.editingState.container); if (targetContainer) { targetContainer.classList.remove('e-comment-editing'); this.setTextAreaState(targetContainer, false); var header = targetContainer.querySelector('.e-comment-header'); if (header) { var headerWrap = header.querySelector('.e-comment-header-wrap'); if (headerWrap) { var indices = this.getIndexesFromContainer(targetContainer); if (indices && indices.length === 2) { var prev = this.isEditing; this.isEditing = false; this.renderHeaderActions(headerWrap, false, getCellAddress(indices[0], indices[1])); this.isEditing = prev; } } } var localBodyHost = this.getBodyHost(targetContainer); if (localBodyHost) { var replyBtns = localBodyHost.querySelectorAll('.e-reply-ddb'); replyBtns.forEach(function (btn) { btn.style.visibility = ''; }); } } this.isEditing = false; this.editingState = null; }; SpreadsheetComment.prototype.deleteReplyById = function (replyId, sourceEl) { if (replyId && sourceEl) { var container = this.getContainer(sourceEl); var host = this.getBodyHost(container); if (container && host) { var indexes = this.getIndexesFromContainer(container); if (indexes && indexes.length === 2) { var row = indexes[0], col = indexes[1]; var cell = getCell(row, col, this.parent.getActiveSheet()); if (cell && cell.comment) { var thread = JSON.parse(JSON.stringify(cell.comment)); if (thread.replies) { var idx = thread.replies.findIndex(function (r) { return r.id === replyId; }); if (idx > -1) { thread.replies.splice(idx, 1); this.saveComment(row, col, thread, 'deleteReply', container.classList.contains('e-pane-container')); var targetListView = getComponent(host, 'listview'); if (targetListView) { targetListView.removeItem({ id: replyId }); } } } } } } } }; SpreadsheetComment.prototype.setTextAreaState = function (container, disabled) { if (container) { var l10n = this.parent.serviceLocator.getService(locale); var textArea = container.querySelector('.e-comment-footer .e-comment-input'); if (textArea) { if (disabled) { textArea.disabled = true; textArea.placeholder = l10n.getConstant('CommentEditingInProgress'); } else { textArea.disabled = false; textArea.placeholder = l10n.getConstant('Reply'); this.adjustTextareaHeight(textArea, false); } } } }; SpreadsheetComment.prototype.adjustTextareaHeight = function (textArea, isEdit) { if (textArea) { var cs = getComputedStyle(textArea); var linePx = parseFloat(cs.lineHeight); if (isNaN(linePx)) { var fontSize = parseFloat(cs.fontSize) || 14; linePx = Math.round(fontSize * 1.2); } var padTB = (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0); var borderTB = (parseFloat(cs.borderTopWidth) || 0) + (parseFloat(cs.borderBottomWidth) || 0); var minLines = 1; var maxLines = 5; if (!isEdit && textArea.value.trim().length === 0) { textArea.style.height = (minLines * linePx) + padTB + borderTB + "px"; textArea.style.overflowY = 'hidden'; return; } textArea.style.height = 'auto'; var contentHeight = Math.max(0, textArea.scrollHeight - padTB); var neededLines = Math.max(1, Math.ceil(contentHeight / Math.max(1, linePx))); var clampedLines = Math.max(minLines, Math.min(maxLines, neededLines)); var finalHeight = (clampedLines * linePx) + padTB + borderTB; textArea.style.height = finalHeight + "px"; textArea.style.overflowY = 'hidden'; } }; SpreadsheetComment.prototype.saveComment = function (rIdx, cIdx, comment, actionName, isPanel) { if (comment && !comment.address) { comment.address = [rIdx, cIdx]; } var sheet = this.parent.getActiveSheet(); var address = getSheetName(this.parent, this.parent.activeSheetIndex) + '!' + getRangeAddress([rIdx, cIdx]); var eventArgs = { comment: JSON.parse(JSON.stringify(comment)), address: address, cancel: false }; this.parent.notify(beginAction, { eventArgs: eventArgs, action: actionName }); if (eventArgs.cancel) { return; } comment = JSON.parse(JSON.stringify(eventArgs.comment)); this.processSheetComments({ sheet: sheet, comment: comment, isDelete: false }); updateCell(this.parent, sheet, { rowIdx: rIdx, colIdx: cIdx, preventEvt: true, cell: { comment: comment } }); var td = this.parent.getCell(rIdx, cIdx); if (td && !td.querySelector('.e-comment-indicator')) { this.createCommentIndicator({ targetEle: td, rIdx: rIdx, cIdx: cIdx }); } if (this.isReviewPaneVisible) { if (actionName === 'addComment') { this.insertThreadIntoPanel(comment); this.scrollToThreadInPanel(comment.id); } else if (!isPanel && actionName !== 'addComment') { this.syncThreadInPanel(comment); } } this.parent.notify(completeAction, { eventArgs: eventArgs, action: actionName }); }; SpreadsheetComment.prototype.detachCommentIndicator = function (rowIdx, colIdx) { var cellElement = this.parent.getCell(rowIdx, colIdx); if (cellElement) { var indicator = cellElement.querySelector('.e-comment-indicator'); if (indicator) { EventHandler.remove(indicator, 'mouseover', this.mouseOver); EventHandler.remove(indicator, 'mouseout', this.mouseOut); delete indicator.dataset.commentListenersAdded; delete indicator.dataset.commentRowIndex; delete indicator.dataset.commentColIndex; detach(indicator); } } }; SpreadsheetComment.prototype.setCommentContainerPosition = function (commentContainer, cellRect) { var selectAllCell = this.parent.element.getElementsByClassName('e-select-all-cell')[0]; var scroller = this.parent.element.getElementsByClassName('e-scroller')[0]; var sheetClientRect = this.parent.element.getElementsByClassName('e-sheet')[0].getBoundingClientRect(); var elementClientRect = this.parent.element.getBoundingClientRect(); var elementPosition = this.parent.element.style.getPropertyValue('position'); var offsetTop = (elementPosition === 'absolute' ? 0 : this.parent.element.offsetTop); var offsetLeft = (elementPosition === 'absolute' ? 0 : this.parent.element.offsetLeft); commentContainer.style.position = 'absolute'; var containerTop = cellRect.top - (elementClientRect.top - offsetTop); if (!isNullOrUndefined(selectAllCell) && !isNullOrUndefined(scroller) && cellRect.top < selectAllCell.getBoundingClientRect().bottom) { containerTop = selectAllCell.getBoundingClientRect().bottom - (elementClientRect.top - offsetTop) + 5; } else if (containerTop < 0) { containerTop = 5; } commentContainer.style.top = containerTop + "px"; var leftPos; var preferredWidth = 244; var actualWidth = preferredWidth; var spaceToRight = sheetClientRect.width - (cellRect.left + cellRect.width - sheetClientRect.left); if (spaceToRight > preferredWidth + 5) { leftPos = cellRect.left + cellRect.width - (elementClientRect.le