Google Docs Comment Counter

Sylas Seabrook

Google Docs Comment Counter

This is a simple Google Docs script that counts the number of comments in a Google Doc and displays the count in a popup dialogue.

Terms of Service

You can do whatever you want with this. Indie Art Creatives LLC shall not be liable for any damages arising from the use of this add-on.

Privacy Policy

Nothing is stored or used in any way. All this add-on does is run a function to count your comments and display it in a popup dialogue, communicating and storing nothing in the process.

Support

No support is provided for this application. Just use the menu that shows up.

Source Code

/** * Comment Counter * * Google Workspace add-on for Google Docs. * Uses per-file drive.file authorization to count comments * without requesting access to the user's entire Google Drive. */ /** * Homepage for the add-on when opened in Google Docs. * * @param {Object} e Google Workspace add-on event object. * @return {Card} */ function onDocsHomepage(e) { return [buildCommentCounterCard_(e)]; } /** * Runs after the user grants drive.file access to the current document. * * @param {Object} e Google Workspace add-on event object. * @return {Card[]} */ function onFileScopeGranted(e) { return [buildCommentCounterCard_(e)]; } /** * Builds the main Comment Counter card. * * If the add-on doesn't yet have access to the current document, * displays a button asking the user to grant access. * * @param {Object} e Google Workspace add-on event object. * @return {Card} */ function buildCommentCounterCard_(e) { const card = CardService.newCardBuilder() .setHeader( CardService.newCardHeader() .setTitle('Comment Counter') .setSubtitle('Count comments in this document') ); const section = CardService.newCardSection(); const docs = e && e.docs ? e.docs : null; if (!docs || !docs.addonHasFileScopePermission) { section.addWidget( CardService.newTextParagraph() .setText( 'Comment Counter needs permission to access this document ' + 'before it can count its comments.' ) ); const permissionAction = CardService.newAction() .setFunctionName('requestFilePermission'); section.addWidget( CardService.newTextButton() .setText('Allow Access to This Document') .setTextButtonStyle(CardService.TextButtonStyle.FILLED) .setOnClickAction(permissionAction) ); card.addSection(section); return card.build(); } section.addWidget( CardService.newTextParagraph() .setText( 'Count unresolved comments or all comments in the current document.' ) ); const activeAction = CardService.newAction() .setFunctionName('countActiveComments'); section.addWidget( CardService.newTextButton() .setText('Count Active Comments') .setOnClickAction(activeAction) ); const allAction = CardService.newAction() .setFunctionName('countAllComments'); section.addWidget( CardService.newTextButton() .setText('Count All Comments') .setOnClickAction(allAction) ); card.addSection(section); return card.build(); } /** * Requests drive.file permission for only the currently open document. * * @return {EditorFileScopeActionResponse} */ function requestFilePermission() { return CardService .newEditorFileScopeActionResponseBuilder() .requestFileScopeForActiveDocument() .build(); } /** * Counts unresolved comments. * * @param {Object} e Google Workspace add-on event object. * @return {ActionResponse} */ function countActiveComments(e) { try { const fileId = getAuthorizedFileId_(e); const counts = getCommentCounts_(fileId); return showNotification_( 'Active comments: ' + counts.active ); } catch (error) { console.error(error); return showNotification_( 'Error: ' + getErrorMessage_(error) ); } } /** * Counts all comments, including resolved comments. * * @param {Object} e Google Workspace add-on event object. * @return {ActionResponse} */ function countAllComments(e) { try { const fileId = getAuthorizedFileId_(e); const counts = getCommentCounts_(fileId); return showNotification_( 'All comments: ' + counts.total ); } catch (error) { console.error(error); return showNotification_( 'Error: ' + getErrorMessage_(error) ); } } /** * Retrieves and counts every page of comments. * * @param {string} fileId Google Drive file ID. * @return {{active: number, total: number}} */ function getCommentCounts_(fileId) { let pageToken = null; let active = 0; let total = 0; do { const options = { fields: 'comments(id,resolved),nextPageToken', pageSize: 100 }; if (pageToken) { options.pageToken = pageToken; } const response = Drive.Comments.list(fileId, options); const comments = response.comments || []; total += comments.length; comments.forEach(function (comment) { if (!comment.resolved) { active++; } }); pageToken = response.nextPageToken || null; } while (pageToken); return { active: active, total: total }; } /** * Gets the current document ID after verifying that file permission exists. * * @param {Object} e Google Workspace add-on event object. * @return {string} */ function getAuthorizedFileId_(e) { if ( !e || !e.docs || !e.docs.addonHasFileScopePermission || !e.docs.id ) { throw new Error( 'Comment Counter does not have permission to access this document.' ); } return e.docs.id; } /** * Creates a Google Workspace notification. * * @param {string} message Notification text. * @return {ActionResponse} */ function showNotification_(message) { return CardService.newActionResponseBuilder() .setNotification( CardService.newNotification() .setText(message) ) .build(); } /** * Returns a useful message from an exception. * * @param {*} error * @return {string} */ function getErrorMessage_(error) { if (error && error.message) { return error.message; } return String(error); }